迭代字母 – C#a-caz

我有一个关于迭代字母表的问题。 我想有一个以“a”开头并以“z”结尾的循环。 之后,循环开始“aa”并计数到“az”。 之后以“ba”开头到“bz”等等……

有人知道一些解决方案吗?

谢谢

编辑:我忘了我给函数一个字符“a”然后函数必须返回b。 如果你给“bnc”那么函数必须返回“bnd”

编辑:完全按照OP的最新编辑要求完成

这是最简单的解决方案,并经过测试:

static void Main(string[] args) { Console.WriteLine(GetNextBase26("a")); Console.WriteLine(GetNextBase26("bnc")); } private static string GetNextBase26(string a) { return Base26Sequence().SkipWhile(x => x != a).Skip(1).First(); } private static IEnumerable Base26Sequence() { long i = 0L; while (true) yield return Base26Encode(i++); } private static char[] base26Chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray(); private static string Base26Encode(Int64 value) { string returnValue = null; do { returnValue = base26Chars[value % 26] + returnValue; value /= 26; } while (value-- != 0); return returnValue; } 

第一次努力,只有az然后aa-zz

 public static IEnumerable GetExcelColumns() { for (char c = 'a'; c <= 'z'; c++) { yield return c.ToString(); } char[] chars = new char[2]; for (char high = 'a'; high <= 'z'; high++) { chars[0] = high; for (char low = 'a'; low <= 'z'; low++) { chars[1] = low; yield return new string(chars); } } } 

请注意,这将停在'zz'。 当然,就循环而言,这里有一些丑陋的重复。 幸运的是,这很容易修复 - 它也可以更加灵活:

第二次尝试:更灵活的字母表

 private const string Alphabet = "abcdefghijklmnopqrstuvwxyz"; public static IEnumerable GetExcelColumns() { return GetExcelColumns(Alphabet); } public static IEnumerable GetExcelColumns(string alphabet) { foreach(char c in alphabet) { yield return c.ToString(); } char[] chars = new char[2]; foreach(char high in alphabet) { chars[0] = high; foreach(char low in alphabet) { chars[1] = low; yield return new string(chars); } } } 

现在,如果你想生成a,b,c,d,aa,ab,ac,ad,ba,......你可以调用GetExcelColumns("abcd")

第三次尝试(进一步修订) - 无限序列

 public static IEnumerable GetExcelColumns(string alphabet) { int length = 0; char[] chars = null; int[] indexes = null; while (true) { int position = length-1; // Try to increment the least significant // value. while (position >= 0) { indexes[position]++; if (indexes[position] == alphabet.Length) { for (int i=position; i < length; i++) { indexes[i] = 0; chars[i] = alphabet[0]; } position--; } else { chars[position] = alphabet[indexes[position]]; break; } } // If we got all the way to the start of the array, // we need an extra value if (position == -1) { length++; chars = new char[length]; indexes = new int[length]; for (int i=0; i < length; i++) { chars[i] = alphabet[0]; } } yield return new string(chars); } } 

它可能是使用递归的更干净的代码,但它不会那么有效。

请注意,如果要在某个点停止,可以使用LINQ:

 var query = GetExcelColumns().TakeWhile(x => x != "zzz"); 

“重启”迭代器

要从给定点重新启动迭代器,您确实可以使用软件SkipWhile建议的SkipWhile 。 当然,那效率很低。 如果你能够在调用之间保持任何状态,你可以保留迭代器(对于任一解决方案):

 using (IEnumerator iterator = GetExcelColumns()) { iterator.MoveNext(); string firstAttempt = iterator.Current; if (someCondition) { iterator.MoveNext(); string secondAttempt = iterator.Current; // etc } } 

或者,您也可以构建代码以使用foreach ,只需突破您可以实际使用的第一个值。

以下内容使用所需的字符串填充列表:

 List result = new List(); for (char ch = 'a'; ch <= 'z'; ch++){ result.Add (ch.ToString()); } for (char i = 'a'; i <= 'z'; i++) { for (char j = 'a'; j <= 'z'; j++) { result.Add (i.ToString() + j.ToString()); } } 

我知道这里有很多答案,其中一个被接受了,但是IMO它们都比它需要的更难。 我认为以下更简单,更清洁:

 static string NextColumn(string column){ char[] c = column.ToCharArray(); for(int i = c.Length - 1; i >= 0; i--){ if(char.ToUpper(c[i]++) < 'Z') break; c[i] -= (char)26; if(i == 0) return "A" + new string(c); } return new string(c); } 

请注意,这不会进行任何输入validation。 如果您不信任您的呼叫者,您应该在开头添加一个IsNullOrEmpty检查,并且c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z'检查循环的顶部。 或者只是留下它,让它成为GIGO 。

您还可以使用这些配套function:

 static string GetColumnName(int index){ StringBuilder txt = new StringBuilder(); txt.Append((char)('A' + index % 26)); //txt.Append((char)('A' + --index % 26)); while((index /= 26) > 0) txt.Insert(0, (char)('A' + --index % 26)); return txt.ToString(); } static int GetColumnIndex(string name){ int rtn = 0; foreach(char c in name) rtn = rtn * 26 + (char.ToUpper(c) - '@'); return rtn - 1; //return rtn; } 

这两个函数是从零开始的。 也就是说,“A”= 0,“Z”= 25,“AA”= 26等。要使它们基于一个(如Excel的COM接口),删除每个函数中注释行上方的行,并取消注释线。

NextColumn函数一样,这些函数不validation其输入。 两者都给你垃圾,如果这是他们得到的。

这就是我想出的。

 ///  /// Return an incremented alphabtical string ///  /// The string to be incremented /// the incremented string public static string NextLetter(string letter) { const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; if (!string.IsNullOrEmpty(letter)) { char lastLetterInString = letter[letter.Length - 1]; // if the last letter in the string is the last letter of the alphabet if (alphabet.IndexOf(lastLetterInString) == alphabet.Length - 1) { //replace the last letter in the string with the first leter of the alphbat and get the next letter for the rest of the string return NextLetter(letter.Substring(0, letter.Length - 1)) + alphabet[0]; } else { // replace the last letter in the string with the proceeding letter of the alphabet return letter.Remove(letter.Length-1).Insert(letter.Length-1, (alphabet[alphabet.IndexOf(letter[letter.Length-1])+1]).ToString() ); } } //return the first letter of the alphabet return alphabet[0].ToString(); } 

只是好奇,为什么不呢

  private string alphRecursive(int c) { var alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray(); if (c >= alphabet.Length) { return alphRecursive(c/alphabet.Length) + alphabet[c%alphabet.Length]; } else { return "" + alphabet[c%alphabet.Length]; } } 

这就像显示一个int,只使用base 26而不是base 10.尝试使用以下算法来查找数组的第n个条目

 q = n div 26; r = n mod 26; s = ''; while (q > 0 || r > 0) { s = alphabet[r] + s; q = q div 26; r = q mod 26; } 

当然,如果您想要前n个条目,这不是最有效的解决方案。 在这种情况下,尝试像丹尼尔的解决方案。

我放了一下,想出了这个:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Alphabetty { class Program { const string alphabet = "abcdefghijklmnopqrstuvwxyz"; static int cursor = 0; static int prefixCursor; static string prefix = string.Empty; static bool done = false; static void Main(string[] args) { string s = string.Empty; while (s != "Done") { s = GetNextString(); Console.WriteLine(s); } Console.ReadKey(); } static string GetNextString() { if (done) return "Done"; char? nextLetter = GetNextLetter(ref cursor); if (nextLetter == null) { char? nextPrefixLetter = GetNextLetter(ref prefixCursor); if(nextPrefixLetter == null) { done = true; return "Done"; } prefix = nextPrefixLetter.Value.ToString(); nextLetter = GetNextLetter(ref cursor); } return prefix + nextLetter; } static char? GetNextLetter(ref int letterCursor) { if (letterCursor == alphabet.Length) { letterCursor = 0; return null; } char c = alphabet[letterCursor]; letterCursor++; return c; } } } 

这是我烹饪过的可能类似的东西。 我正在尝试迭代计数,以便设计尽可能小的编号模式,但给了我足够的唯一性。

我知道每次增加一个Alpha字符,它会增加26x的可能性,但我不确定有多少字母,数字或我想要使用的模式。

这导致我下面的代码。 基本上你传递一个AlphaNumber字符串,每个有一个Letter的位置最终会增加到“z \ Z”,每个有一个数字的位置最终会增加到“9”。

所以你可以用两种方式来称呼它..

 //This would give you the next Itteration... (H3reIsaStup4dExamplf) string myNextValue = IncrementAlphaNumericValue("H3reIsaStup4dExample") //Or Loop it resulting eventually as "Z9zzZzzZzzz9zZzzzzzz" string myNextValue = "H3reIsaStup4dExample" while (myNextValue != null) { myNextValue = IncrementAlphaNumericValue(myNextValue) //And of course do something with this like write it out } 

(对我来说,我做的事情就像“1AA000”)

 public string IncrementAlphaNumericValue(string Value) { //We only allow Characters ab, AZ, 0-9 if (System.Text.RegularExpressions.Regex.IsMatch(Value, "^[a-zA-Z0-9]+$") == false) { throw new Exception("Invalid Character: Must be aZ or 0-9"); } //We work with each Character so it's best to convert the string to a char array for incrementing char[] myCharacterArray = Value.ToCharArray(); //So what we do here is step backwards through the Characters and increment the first one we can. for (Int32 myCharIndex = myCharacterArray.Length - 1; myCharIndex >= 0; myCharIndex--) { //Converts the Character to it's ASCII value Int32 myCharValue = Convert.ToInt32(myCharacterArray[myCharIndex]); //We only Increment this Character Position, if it is not already at it's Max value (Z = 90, z = 122, 57 = 9) if (myCharValue != 57 && myCharValue != 90 && myCharValue != 122) { myCharacterArray[myCharIndex]++; //Now that we have Incremented the Character, we "reset" all the values to the right of it for (Int32 myResetIndex = myCharIndex + 1; myResetIndex < myCharacterArray.Length; myResetIndex++) { myCharValue = Convert.ToInt32(myCharacterArray[myResetIndex]); if (myCharValue >= 65 && myCharValue <= 90) { myCharacterArray[myResetIndex] = 'A'; } else if (myCharValue >= 97 && myCharValue <= 122) { myCharacterArray[myResetIndex] = 'a'; } else if (myCharValue >= 48 && myCharValue <= 57) { myCharacterArray[myResetIndex] = '0'; } } //Now we just return an new Value return new string(myCharacterArray); } } //If we got through the Character Loop and were not able to increment anything, we retun a NULL. return null; } 

这是我使用递归的尝试:

 public static void PrintAlphabet(string alphabet, string prefix) { for (int i = 0; i < alphabet.Length; i++) { Console.WriteLine(prefix + alphabet[i].ToString()); } if (prefix.Length < alphabet.Length - 1) { for (int i = 0; i < alphabet.Length; i++) { PrintAlphabet(alphabet, prefix + alphabet[i]); } } } 

然后简单地调用PrintAlphabet("abcd", "") ;