【问题标题】:Logic to generate an alphabetical sequence in C# [closed]在 C# 中生成字母序列的逻辑 [关闭]
【发布时间】:2015-05-14 07:34:07
【问题描述】:

顺序应该是这样的。
A-Z,AA-AZ,BA-BZ,CA-CZ,.......,ZA-ZZ
ZZ 之后应该从 AAA 开始。
然后 AAAZZZ,然后 AAAAZZZZ 等等。

此序列非常类似于 Excel 工作表。

编辑:添加我的代码

        private void SequenceGenerator()
    {
        var numAlpha = new Regex("(?<Numeric>[0-9]*)(?<Alpha>[a-zA-Z]*)");
        var match = numAlpha.Match(txtBNo.Text);

        var alpha = match.Groups["Alpha"].Value;
        var num = Convert.ToInt32(match.Groups["Numeric"].Value);
        lastChar = alpha.Substring(alpha.Length - 1);

        if (lastChar=="Z")
        {
            lastChar = "A";
            txtBNo.Text = num.ToString() + "A" + alpha.Substring(0, alpha.Length - 1) + lastChar;
        }

        else
        {
            txtBNo.Text = num.ToString() + alpha.Substring(0, alpha.Length - 1) + Convert.ToChar(Convert.ToInt32(Convert.ToChar(lastChar)) + 1);
        }
    }

这就是我所做的。但是,我知道这是一个错误的逻辑。

谢谢。

【问题讨论】:

标签: c# sequences alphabetical sequencing sequence-generators


【解决方案1】:

正如我在评论中所写,这是一个基本转换问题,您的输出为 base-26,符号为 A-Z

static string NumToLetters(int num)
{
    string str = string.Empty;

    // We need to do at least a "round" of division
    // to handle num == 0
    do
    {
        // We have to "prepend" the new digit
        str = (char)('A' + (num % 26)) + str;
        num /= 26;
    }
    while (num != 0);

    return str;
}

【讨论】:

    【解决方案2】:

    你很幸运,我以前做过一次。我遇到的问题是在 Excel 表中没有 0,甚至在双“数字”“数字”中也没有。这意味着您从 a(即 1)开始,然后从 z(即 26)直接进入 aa(27)。这就是不是一个简单的基本转换问题的原因,您需要一些额外的代码来处理这个问题。 测试 xanatos 建议的函数结果如下:

    NumToLetters(0) --> A

    NumToLetters(25) --> Z

    NumToLetters(26) --> BA

    我的解决方案有更多代码,但它已经过针对 Excel 的测试并且完全兼容,除了它以 0 而不是 1 开头,这意味着 a 是 0,z 是 25,aa 是 26,zz 701,aaa 是 702 和很快)。如果你愿意,你可以把它改成从 1 开始,这很简单。

    private static string mColumnLetters = "zabcdefghijklmnopqrstuvwxyz";
    
    // Convert Column name to 0 based index
    public static int ColumnIndexByName(string ColumnName)
        {
            string CurrentLetter;
            int ColumnIndex, LetterValue, ColumnNameLength;
            ColumnIndex = -1; // A is the first column, but for calculation it's number is 1 and not 0. however, Index is alsways zero-based.
            ColumnNameLength = ColumnName.Length;
            for (int i = 0; i < ColumnNameLength; i++)
            {
                CurrentLetter = ColumnName.Substring(i, 1).ToLower();
                LetterValue = mColumnLetters.IndexOf(CurrentLetter);
                ColumnIndex += LetterValue * (int)Math.Pow(26, (ColumnNameLength - (i + 1)));
            }
            return ColumnIndex;
        }
    
    // Convert 0 based index to Column name
    public static string ColumnNameByIndex(int ColumnIndex)
        {
            int ModOf26, Subtract;
            StringBuilder NumberInLetters = new StringBuilder();
            ColumnIndex += 1; // A is the first column, but for calculation it's number is 1 and not 0. however, Index is alsways zero-based.
            while (ColumnIndex > 0)
            {
                if (ColumnIndex <= 26)
                {
                    ModOf26 = ColumnIndex;
                    NumberInLetters.Insert(0, mColumnLetters.Substring(ModOf26, 1));
                    ColumnIndex = 0;
                }
                else
                {
                    ModOf26 = ColumnIndex % 26;
                    Subtract = (ModOf26 == 0) ? 26 : ModOf26;
                    ColumnIndex = (ColumnIndex - Subtract) / 26;
                    NumberInLetters.Insert(0, mColumnLetters.Substring(ModOf26, 1));
                }
            }
            return NumberInLetters.ToString().ToUpper();
        }
    

    【讨论】:

    • 您的代码只需稍作修改即可工作。 :)
    【解决方案3】:

    试试这个方法:

    public static IEnumerable<string> GenerateItems()
    {
        var buffer = new[] { '@' };
        var maxIdx = 0;
        while(true)
        {
            var i = maxIdx;
            while (true)
            {
                if (buffer[i] < 'Z')
                {
                    buffer[i]++;
                    break;
                }
    
                if (i == 0)
                {
                    buffer = Enumerable.Range(0, ++maxIdx + 1).Select(c => 'A').ToArray();
                    break;
                }
    
                buffer[i] = 'A';
                i--;
            }
    
            yield return new string(buffer);
        }
        // ReSharper disable once FunctionNeverReturns
    }
    

    这是您需要的无限生成器您必须限制项目的数量,如下所示:

    var sequence = GenerateItems().Take(10000).ToArray();
    

    不要这样称呼它(它会导致无限循环):

    foreach (var i in GenerateItems())
        Console.WriteLine(i);
    

    【讨论】:

    • 这是一个不错的解决方案,但您只需要使用最后一个单元格的值。
    • “但是你只需要使用最后一个单元格的值” - 我想我不明白你,你能解释一下吗?
    • 尝试运行您的解决方案。您将获得一个字符串数组,其中包含 A 到所需值之间的所有值。所以如果你像这样运行它 var sequence = GenerateItems().Take(4).ToArray();你会得到一个像这样的数组:{"A", "B", "C", "D"}。
    • 是的,当然,它是有问题的,不是吗?我可以添加一些跳过逻辑来实现 startFrom 功能。
    • 也许你是对的,我错过了。我建议了一种将单个数字转换为字符串表示并返回的方法,但也许我误解了这个问题。
    猜你喜欢
    • 2021-07-10
    • 1970-01-01
    • 2017-01-17
    • 2011-11-09
    • 2017-04-13
    • 2012-02-01
    • 2016-03-14
    • 1970-01-01
    • 2011-11-11
    相关资源
    最近更新 更多