如何通过所有可能性增加java String?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/342052/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to increment a java String through all the possibilities?
提问by dacracot
I need to increment a String in java from "aaaaaaaa" to "aaaaaab" to "aaaaaac" up through the alphabet, then eventually to "aaaaaaba" to "aaaaaabb" etc. etc.
我需要将 java 中的字符串从“aaaaaaaa”增加到“aaaaaab”到“aaaaaac”,然后通过字母表,最终到“aaaaaaba”到“aaaaaabb”等等。
Is there a trick for this?
这有什么窍门吗?
采纳答案by Clayton
It's not much of a "trick", but this works for 4-char strings. Obviously it gets uglier for longer strings, but the idea is the same.
这不是什么“技巧”,但这适用于 4 个字符的字符串。显然,更长的字符串会变得更丑,但想法是一样的。
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);
}
}
}
}
回答by Nicholas Mancuso
I would create a character array and increment the characters individually. Strings are immutable in Java, so each change would create a new spot on the heap resulting in memory growing and growing.
我会创建一个字符数组并单独增加字符。字符串在 Java 中是不可变的,因此每次更改都会在堆上创建一个新位置,从而导致内存越来越大。
With a character array, you shouldn't have that problem...
使用字符数组,你不应该有这个问题......
回答by Pyrolistical
Have an array of byte that contain ascii values, and have loop that increments the far right digit while doing carry overs.
有一个包含 ascii 值的字节数组,并有一个循环,在执行结转时增加最右边的数字。
Then create the string using
然后使用创建字符串
public String(byte[] bytes, String charsetName)
Make sure you pass in the charset as US-ASCII or UTF-8 to be unambiguous.
确保将字符集作为 US-ASCII 或 UTF-8 传递,以确保无歧义。
回答by Joachim Sauer
You're basically implementing a Base 26 number systemwith leading "zeroes" ("a").
您基本上是在实现带有前导“零”(“a”)的Base 26 数字系统。
You do it the same way you convert a int to a base-2 or base-10 String, but instead of using 2 or 10, you use 26 and instead of '0' as your base, you use 'a'.
这样做的方法与将 int 转换为 base-2 或 base-10 字符串的方式相同,但不是使用 2 或 10,而是使用 26,而不是使用 '0' 作为基数,而是使用 'a'。
In Java you can easily use this:
在 Java 中,您可以轻松地使用它:
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();
}
The basic idea then is to not store the String, but just some counter (int an int or a long, depending on your requirements) and to convert it to the String as needed. This way you can easily increase/decrease/modify your counter without having to parse and re-create the String.
基本思想是不存储字符串,而只存储一些计数器(int 或 int,具体取决于您的要求)并根据需要将其转换为字符串。通过这种方式,您可以轻松地增加/减少/修改您的计数器,而无需解析和重新创建字符串。
回答by Adam Rosenfield
Increment the last character, and if it reaches Z, reset it to A and move to the previous characters. Repeat until you find a character that's not Z. Because Strings are immutable, I suggest using an array of characters instead to avoid allocating lots and lots of new objects.
增加最后一个字符,如果到达 Z,则将其重置为 A 并移动到前一个字符。重复直到找到不是 Z 的字符。因为字符串是不可变的,所以我建议使用字符数组来避免分配大量新对象。
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';
}
}
回答by Ande Turner
Just expanding on the examples, as to Implementation, consider putting this into a Class... Each time you call toString of the Class it would return the next value:
只是扩展示例,至于实现,请考虑将其放入类...每次调用类的 toString 时,它都会返回下一个值:
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();
}
}
回答by Ray Tayek
you can use big integer's toString(radix) method like:
您可以使用大整数的 toString(radix) 方法,例如:
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;
}
回答by Rob Rolnick
I'd have to agree with @saua's approach if you only wanted the final result, but here is a slight variation on it in the case you want every result.
如果您只想要最终结果,我将不得不同意 @saua 的方法,但如果您想要每个结果,这里有一些细微的变化。
Note that since there are 26^8 (or 208827064576) different possible strings, I doubt you want them all. That said, my code prints them instead of storing only one in a String Builder. (Not that it really matters, though.)
请注意,由于有 26^8(或 208827064576)个不同的可能字符串,我怀疑您是否想要全部。也就是说,我的代码会打印它们,而不是只在 String Builder 中存储一个。(不过,这并不重要。)
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);
}
回答by cyberz
The following code uses a recursive approach to get the next string (let's say, from "aaaa" to "aaab" and so on) without the need of producing all the previous combinations, so it's rather fast and it's not limited to a given maximum string length.
以下代码使用递归方法来获取下一个字符串(比方说,从“aaaa”到“aaab”等等)而不需要生成所有先前的组合,因此它相当快并且不限于给定的最大值字符串长度。
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;
}
}
As some folks pointed out, this is tail recursive, so you can reformulate it replacing the recursion with a loop.
正如一些人指出的那样,这是尾递归,因此您可以重新制定它,用循环替换递归。
回答by geoand
Building on the solution by @cyberz, the following code is an example of how you could write a recursive call which can be optimized by a compiler that supports Tail Recursion.
基于@cyberz 的解决方案,以下代码是如何编写递归调用的示例,该调用可由支持Tail Recursion的编译器优化。
The code is written in Groovy, since it runs on the JVM, its syntax closely resembles Java and it's compiler supports tail recursion optimization
代码是用 Groovy 编写的,因为它运行在 JVM 上,它的语法与 Java 非常相似,并且它的编译器支持尾递归优化
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)
}