Iterating through the Alphabet - C# a-caz

后端 未结 10 1056
無奈伤痛
無奈伤痛 2020-11-29 03:03

I have a question about iterate through the Alphabet. I would like to have a loop that begins with \"a\" and ends with \"z\". After that, the loop begins \"aa\" and count to

相关标签:
10条回答
  • 2020-11-29 03:32

    Here is something I had cooked up that may be similar. I was experimenting with iteration counts in order to design a numbering schema that was as small as possible, yet gave me enough uniqueness.

    I knew that each time a added an Alpha character, it would increase the possibilities 26x but I wasn't sure how many letters, numbers, or the pattern I wanted to use.

    That lead me to the code below. Basically you pass it an AlphaNumber string, and every position that has a Letter, would eventually increment to "z\Z" and every position that had a Number, would eventually increment to "9".

    So you can call it 1 of two ways..

    //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
    }
    

    (For me, I was doing something like "1AA000")

    public string IncrementAlphaNumericValue(string Value)
        {
            //We only allow Characters a-b, A-Z, 0-9
            if (System.Text.RegularExpressions.Regex.IsMatch(Value, "^[a-zA-Z0-9]+$") == false)
            {
                throw new Exception("Invalid Character: Must be a-Z 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;  
        }
    
    0 讨论(0)
  • 2020-11-29 03:33

    Here’s what I came up with.

    /// <summary>
    /// Return an incremented alphabtical string
    /// </summary>
    /// <param name="letter">The string to be incremented</param>
    /// <returns>the incremented string</returns>
    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();
    }
    
    0 讨论(0)
  • 2020-11-29 03:34

    I know there are plenty of answers here, and one's been accepted, but IMO they all make it harder than it needs to be. I think the following is simpler and cleaner:

    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);
    }
    

    Note that this doesn't do any input validation. If you don't trust your callers, you should add an IsNullOrEmpty check at the beginning, and a c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' check at the top of the loop. Or just leave it be and let it be GIGO.

    You may also find use for these companion functions:

    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;
    }
    

    These two functions are zero-based. That is, "A" = 0, "Z" = 25, "AA" = 26, etc. To make them one-based (like Excel's COM interface), remove the line above the commented line in each function, and uncomment those lines.

    As with the NextColumn function, these functions don't validate their inputs. Both with give you garbage if that's what they get.

    0 讨论(0)
  • 2020-11-29 03:35

    Here's my attempt using recursion:

    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]);
            }
        }
    }
    

    Then simply call PrintAlphabet("abcd", "");

    0 讨论(0)
  • 2020-11-29 03:36

    Edit: Made it do exactly as the OP's latest edit wants

    This is the simplest solution, and tested:

    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<string> 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;
    }
    
    0 讨论(0)
  • 2020-11-29 03:36

    I gave this a go and came up with this:

    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;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题