2008-12-04 22 views
17

Ho bisogno di incrementare una stringa in Java da "aaaaaaaa" a "aaaaaab" a "aaaaaac" attraverso l'alfabeto, poi alla fine a "aaaaaaba" a "aaaaaabb" ecc eccCome incrementare una stringa java attraverso tutte le possibilità?

C'è un trucco per Questo?

+10

Ricordare che il cracking della password brute-force non è etico. – bzlm

+4

non importa, perché quando ha raggiunto zzzzzzzz non sarà né etico né immorale, ma morto. – hop

+0

zzzzzzzz = addormentato, no? : p –

risposta

-3

Non è molto un "trucco", ma funziona per le stringhe di 4 caratteri. Ovviamente diventa più brutto per stringhe più lunghe, ma l'idea è la stessa.

char array[] = new char[4]; 
for (char c0 = 'a'; c0 <= 'z'; c0++) { 
    array[0] = c0; 
    for (char c1 = 'a'; c1 <= 'z'; c1++) { 
    array[1] = c1; 
    for (char c2 = 'a'; c2 <= 'z'; c2++) { 
     array[2] = c2; 
     for (char c3 = 'a'; c3 <= 'z'; c3++) { 
     array[3] = c3; 
     String s = new String(array); 
     System.out.println(s); 
     } 
    } 
    } 
} 
+0

Funzionerà in java o è un costrutto C? – dacracot

+0

Funziona in java ... brutto a volte è meglio. – dacracot

+0

Questo è più veloce e più facile da capire. Meno è meglio. – dacracot

0

Vorrei creare un array di caratteri e incrementare i caratteri individualmente. Le stringhe sono immutabili in Java, quindi ogni modifica creerebbe un nuovo punto sull'heap con conseguente aumento e aumento della memoria.

Con un array di caratteri, non dovrebbe avere questo problema ...

0

hanno una serie di byte che contengono valori ASCII, e hanno ciclo che incrementa la cifra più a destra, mentre facendo riporti.

quindi creare la stringa utilizzando

public String(byte[] bytes, String charsetName) 

assicurarsi di passare nel charset come US-ASCII o UTF-8 per essere inequivocabile.

52

Stai praticamente implementando uno Base 26 number system con "zero" iniziali ("a").

Lo si fa nello stesso modo in cui si converte una stringa int in una stringa base-2 o base-10, ma invece di usare 2 o 10, si usa 26 e invece di '0' come base, si usa 'a '.

In Java si può facilmente utilizzare questo:

public static String base26(int num) { 
    if (num < 0) { 
    throw new IllegalArgumentException("Only positive numbers are supported"); 
    } 
    StringBuilder s = new StringBuilder("aaaaaaa"); 
    for (int pos = 6; pos >= 0 && num > 0 ; pos--) { 
    char digit = (char) ('a' + num % 26); 
    s.setCharAt(pos, digit); 
    num = num/26; 
    } 
    return s.toString(); 
} 

L'idea di base è quindi di non memorizzare la stringa, ma solo alcuni contatore (int un int o un lungo, a seconda delle esigenze) e per convertire alla stringa, se necessario. In questo modo puoi facilmente aumentare/diminuire/modificare il tuo contatore senza dover analizzare e ricreare la stringa.

+0

Grazie, dacracot, per la correzione. Il codice non era ovviamente ben testato. –

+0

sì, e poi un giorno si raggiunge maxint ... – hop

+1

Integer.MAX_VALUE = agytisyx In realtà mi piace ;-) –

3

Incrementa l'ultimo carattere, e se raggiunge Z, reimpostalo su A e passa ai caratteri precedenti. Ripeti finché non trovi un personaggio che non è Z. Poiché le stringhe sono immutabili, ti suggerisco di utilizzare una serie di caratteri per evitare di allocare un sacco di nuovi oggetti.

public static void incrementString(char[] str) 
{ 
    for(int pos = str.length - 1; pos >= 0; pos--) 
    { 
     if(Character.toUpperCase(str[pos]) != 'Z') 
     { 
      str[pos]++; 
      break; 
     } 
     else 
      str[pos] = 'a'; 
    } 
} 
+0

il ramo else deve impostare str [pos] = 'a'; –

+0

@ Martin: Whoops, buona cattura. –

0

Basta espansione sugli esempi, da implementazione, considerare di mettere questo in una classe ... Ogni volta che si chiama toString della classe che sarebbe tornato il valore successivo:

public class Permutator { 

    private int permutation; 

    private int permutations; 

    private StringBuilder stringbuilder; 

    public Permutator(final int LETTERS) { 

     if (LETTERS < 1) { 
      throw new IllegalArgumentException("Usage: Permutator(\"1 or Greater Required\" \)"); 
     } 

     this.permutation = 0; 

     // MAGIC NUMBER : 26 = Number of Letters in the English Alphabet 
     this.permutations = (int) Math.pow(26, LETTERS); 

     this.stringbuilder = new StringBuilder(); 

     for (int i = 0; i < LETTERS; ++i) { 
      this.stringbuilder.append('a'); 
     } 
    } 

    public String getCount() { 

     return String.format("Permutation: %s of %s Permutations.", this.permutation, this.permutations); 
    } 

    public int getPermutation() { 

     return this.permutation; 
    } 

    public int getPermutations() { 

     return this.permutations; 
    } 

    private void permutate() { 

     // TODO: Implement Utilising one of the Examples Posted. 
    } 

    public String toString() { 

     this.permutate(); 

     return this.stringbuilder.toString(); 
    } 
}  
+1

Invece di quel commento si potrebbe facilmente avere un costante 'statico finale pubblico int NUMBER_OF_LETTERS_IN_THE_ENGLISH_ALPHABET = 26;'. –

1

è possibile utilizzare il metodo grande toString di numero intero (radix) come:

import java.math.BigInteger; 
public class Strings { 
    Strings(final int digits,final int radix) { 
     this(digits,radix,BigInteger.ZERO); 
    } 
    Strings(final int digits,final int radix,final BigInteger number) { 
     this.digits=digits; 
     this.radix=radix; 
     this.number=number; 
    } 
    void addOne() { 
     number=number.add(BigInteger.ONE); 
    } 
    public String toString() { 
     String s=number.toString(radix); 
     while(s.length()<digits) 
      s='0'+s; 
     return s; 
    } 
    public char convert(final char c) { 
     if('0'<=c&&c<='9') 
      return (char)('a'+(c-'0')); 
     else if('a'<=c&&c<='p') 
      return (char)(c+10); 
     else throw new RuntimeException("more logic required for radix: "+radix); 
    } 
    public char convertInverse(final char c) { 
     if('a'<=c&&c<='j') 
      return (char)('0'+(c-'a')); 
     else if('k'<=c&&c<='z') 
      return (char)(c-10); 
     else throw new RuntimeException("more logic required for radix: "+radix); 
    } 
    void testFix() { 
     for(int i=0;i<radix;i++) 
      if(convert(convertInverse((char)('a'+i)))!='a'+i) 
       throw new RuntimeException("testFix fails for "+i); 
    } 
    public String toMyString() { 
     String s=toString(),t=""; 
     for(int i=0;i<s.length();i++) 
      t+=convert(s.charAt(i)); 
     return t; 
    } 
    public static void main(String[] arguments) { 
     Strings strings=new Strings(8,26); 
     strings.testFix(); 
     System.out.println(strings.number.toString()+' '+strings+' '+strings.toMyString()); 
     for(int i=0;i<Math.pow(strings.radix,3);i++) 
      try { 
       strings.addOne(); 
       if(Math.abs(i-i/strings.radix*strings.radix)<2) 
        System.out.println(strings.number.toString()+' '+strings+' '+strings.toMyString()); 
      } catch(Exception e) { 
       System.out.println(""+i+' '+strings+" failed!"); 
      } 
    } 
    final int digits,radix; 
    BigInteger number; 
} 
+0

troppo complicato, probabilmente al di sopra della testa degli OP. metti almeno alcuni commenti lì dentro! – hop

+0

Sopra la mia testa, pleeeeeeeeeeeeeeeeeease. Provandolo da quando la risposta (finora) accettata ha colpito maxint. – dacracot

+0

sto usando lo stesso trucco di base 26 per ottenere il numero nella base 26. Ho bisogno di convertire i caratteri in ciò che vuole il manifesto (quindi convertire e convertireInverse). sarà necessario modificare il ciclo for in modo che io sia un grande decimale se si desidera andare fino a zzzzzzzz. –

1

avrei dovuto essere d'accordo con @ di saua approccio se si voleva solo il risultato finale, ma qui è una leggera variazione su di esso, nel caso si desidera che ogni risultato .

Si noti che poiché ci sono 26^8 (o 208827064576) diverse stringhe possibili, dubito che le volete tutte. Detto questo, il mio codice li stampa invece di memorizzarne solo uno in un generatore di stringhe. (Non che sia davvero importante, però.)

public static void base26(int maxLength) { 
    buildWord(maxLength, ""); 
    } 
    public static void buildWord(int remaining, String word) 
    { 
    if (remaining == 0) 
    { 
     System.out.println(word); 
    } 
    else 
    { 
     for (char letter = 'A'; letter <= 'Z'; ++letter) 
     { 
     buildWord(remaining-1, word + letter); 
     } 
    } 
    } 

    public static void main(String[] args) 
    { 
    base26(8); 
    } 
13

Il codice seguente utilizza un metodo ricorsivo per ottenere la stringa successiva (diciamo, da "AAAA" a "AAAB" e così via), senza la necessità di produrre tutte le combinazioni precedenti, quindi è piuttosto veloce e non è limitato a una determinata lunghezza massima della stringa.

public class StringInc { 
public static void main(String[] args) { 
    System.out.println(next("aaa")); // Prints aab 

    System.out.println(next("abcdzz")); // Prints abceaa 

    System.out.println(next("zzz")); // Prints aaaa 
} 

public static String next(String s) { 
    int length = s.length(); 
    char c = s.charAt(length - 1); 

    if(c == 'z') 
    return length > 1 ? next(s.substring(0, length - 1)) + 'a' : "aa"; 

    return s.substring(0, length - 1) + ++c; 
} 
} 
0

Questo codice dovrebbe funzionare per una stringa di qualsiasi dimensione.

public static String iterateAlphabetic(String input) { 
      String output = input.toUpperCase(); 
      char[] array = output.toCharArray(); 
      boolean overflow = true; 
      for(int itr=array.length-1; itr>=0; itr--) { 
       if(overflow && array[itr]=='Z') { 
        array[itr] = 'A'; 
        overflow = true; 
        continue; 
       } 
       if(overflow) { 
        array[itr] = next(alphabeticUpper,array[itr]); 
        overflow = false; 
        continue; 
       } 
       break; 
      }  
      if(overflow) 
       output = "A" + new String(array); 
      else 
       output = new String(array); 
      if(output.length() < input.length()) 
       output = StringUtil.padding(output, 'A', input.length()); 
      return output; 
     } 

public static String padding(String input, char pad, int width) { 
    if (width < 0) 
     throw new IllegalArgumentException("width must be > 0"); 

    if (width < input.length()) 
     return input; 

    StringBuilder sb = new StringBuilder(); 
    for(int i = 0;i < (width - input.length()); i++) { 
     sb.append(pad); 
    } 
    sb.append(input); 
    return sb.toString(); 
} 
0

Costruire sulla soluzione da @cyberz, il seguente codice è un esempio di come si potrebbe scrivere una chiamata ricorsiva che può essere ottimizzato da un compilatore che supporta Tail Recursion.

Il codice è scritto in Groovy, dal momento che gira su JVM, la sua sintassi è molto simile Java ed è compilatore supporta l'ottimizzazione ricorsione in coda

static String next(String input) { 
    return doNext(input, "") 
} 

@TailRecursive 
@CompileStatic 
static String doNext(String input, String result) { 
    if(!self) { 
     return result 
    } 

    final String last = input[-1] 
    final String nonLast = self.substring(0, input.size()-1) 
    if('z' == last) { 
     return doNext(nonLast, (nonLast ? 'a' : 'aa') + result) 
    } 

    return doNext('', nonLast + (((last as Character) + 1) as Character).toString() + result) 
} 
0

Dal momento che nessuna delle risposte erano utile per me, ho scritto il mio codice proprio:

/** 
* Increases the given String value by one. Examples (with min 'a' and max 'z'): <p> 
* 
* - "aaa" -> "aab" <br> 
* - "aab" -> "aac" <br> 
* - "aaz" -> "aba" <br> 
* - "zzz" -> "aaaa" <br> 
* 
* @param s 
* @param min lowest char (a zero) 
* @param max highest char (e.g. a 9, in a decimal system) 
* @return increased String by 1 
*/ 
public static String incString(String s, char min, char max) { 
    char last = s.charAt(s.length() - 1); 
    if (++last > max) 
     return s.length() > 1 ? incString(s.substring(0, s.length()-1), min, max) + min : "" + min + min; 
    else 
     return s.substring(0, s.length()-1) + last; 
} 
Problemi correlati