【问题标题】:What's the fastest way to remove characters from an alpha-numeric string?从字母数字字符串中删除字符的最快方法是什么?
【发布时间】:2017-05-19 08:30:19
【问题描述】:

假设我们将以下字符串作为参数传递给下面的函数:

string sString = "S104";
string sString2 = "AS105";
string sString3 = "ASRVT106";

我希望能够从string 中提取数字并将它们放入int 变量中。有没有比下面的代码更快和/或更有效的方法从字符串中删除字母?:(*这些字符串将在运行时动态填充 - 它们在构造时没有被赋值。)

代码:

public GetID(string sCustomTag = null)
{
    m_sCustomTag = sCustomTag;
    try {
        m_lID = Convert.ToInt32(m_sCustomTag); }
        catch{
            try{
                int iSubIndex = 0;     
                char[] subString = sCustomTag.ToCharArray(); 

                //ITERATE THROUGH THE CHAR ARRAY
                for (int i = 0; i < subString.Count(); i++)     
                {
                    for (int j = 0; j < 10; j++)
                    {
                        if (subString[i] == j)
                        {
                            iSubIndex = i;
                            goto createID;
                        }
                    }
                }

            createID: m_lID = Convert.ToInt32(m_sCustomTag.Substring(iSubIndex));
            }
            //IF NONE OF THAT WORKS...
            catch(Exception e)
            {
                m_lID = 00000;
                throw e;
            }
         }
     }
 }

我以前做过这样的事情,但我不确定是否有更有效的方法来做到这一点。如果开头只是一个字母,我可以每次都将subStringIndex 设置为 1,但用户基本上可以输入任何他们想要的内容。通常,它们将被格式化为 LETTER-then-NUMBER 格式,但如果他们不这样做,或者他们想输入多个字母,例如 sString2sString3,那么我需要能够弥补这一点。此外,如果用户输入一些像string sString 4 = S51A24; 这样的破旧的非传统格式,有没有办法从字符串中删除所有字母?

我四处寻找,在 MSDNGoogle 上找不到任何东西。非常感谢任何帮助或链接!

【问题讨论】:

  • 你为什么在代码中使用goto只是好奇
  • 使用正则表达式......
  • 我使用它而不是break,因为它在嵌套的 for 循环中,我想要一个数字的第一个实例。我觉得 break 会找到第一个数字,然后继续遍历 char[] 的其余部分,这是我不想要的,因为我不希望 iSubIndex 被重新分配。
  • @GeoffOverfield google.. 是什么?互联网上也有很多关于如何从字符串中提取数字的例子,这里有 1 个 stackoverflow.com/questions/4734116/…
  • 这里有一个解决方案... http://stackoverflow.com/a/273144/3877877 .... 简而言之Regex.Replace(input, @"[^\d+$]", "");

标签: c# string data-manipulation


【解决方案1】:

您可以使用正则表达式。它不一定更快,但更简洁。

string sString = "S104";
string sString2 = "AS105";
string sString3 = "ASRVT106";

var re = new Regex(@"\d+");

Console.WriteLine(re.Match(sString).Value); // 104
Console.WriteLine(re.Match(sString2).Value); // 105
Console.WriteLine(re.Match(sString3).Value); // 106

【讨论】:

  • 谢谢。我明天回去工作时会试试这个。
  • 如果字符串的格式没有改变,这很好用,它符合 OP 的问题。例如,“AS12BD4”等其他格式将不起作用...
【解决方案2】:

您可以使用Regex,但这样做可能更快:

public int ExtractInteger(string str)
{
    var sb = new StringBuilder();
    for (int i = 0; i < str.Length; i++)
        if(Char.IsDigit(str[i])) sb.Append(str[i]);
    return int.Parse(sb.ToString());
}

您可以使用一些 LINQ 进一步简化,但会降低性能:

public int ExtractInteger(string str)
{
    return int.Parse(new String(str.Where(c=>Char.IsDigit(c)).ToArray()));
}

现在,如果您只想解析第一个连续数字序列,请改为:

public int ExtractInteger(string str)
{
    return int.Parse(new String(str.SkipWhile(c=>!Char.IsDigit(c)).TakeWhile(c=>Char.IsDigit(c)).ToArray()));
}

【讨论】:

  • 您的帖子一直受到上下投票的打击 :-)
  • 反对者:您愿意解释一下这是怎么回事吗?
  • 谢谢。我明天回去工作时会试试这个。
  • 赞成我,因为您的解决方案也会通过其他格式。
【解决方案3】:
    string removeLetters(string s)
    {
        for (int i = 0; i < s.Length; i++)
        {
            char c = s[i];

            if (IsEnglishLetter(c))
            {
                s = s.Remove(i, 1);
            }
        }

        return s;
    }

    bool IsEnglishLetter(char c)
    {
        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
    }

【讨论】:

  • 谢谢。我明天回去工作时会试试这个。
  • 请注意,由于string 是一个不可变类,因此每次删除一个字符 (s.Remove(i, 1)) 时,您实际上是在实例化一个新对象,这会使此代码变慢。
【解决方案4】:

当您问“删除字符的最快方法是什么……”时,您真正想说的是“如何通过仅从字符串中提取数字来创建整数”。

按照这个假设,您对Convert.ToInt32 的第一次调用会因为抛出异常而导致您有数字以外的情况。改成

        if (int.TryParse(sCustomTag, out m_lID))
            return;

然后您可以使用in-place unsafe iteration of the characters of the string(这使用fixed 并避免ToCharArray() 中的数据复制),提取数字,然后转换它们。它避免了StringBuilder 的分配,并且比以通常的方式迭代字符串要快一些。

这是一个可复制/粘贴的版本:

    public static unsafe int GetNumber(string s)
    {
        int number;
        if (int.TryParse(s, out number))
            return number;

        int value = 0;
        fixed (char* pString = s)
        {
            var pChar = pString;
            for (int i = 0; i != s.Length; i++, pChar++)
            {
                if (*pChar < '\u0030' || *pChar > '\u0039') continue;
                value = value * 10 + *pChar - '\u0030';
            }
        }

        return value;
    } 

如果您知道数字总是在开头,请将continue 更改为break;如果数字总是在末尾,迭代 向后,转换每个单独的数字,将该数字乘以 10 的适当幂,然后添加到累积结果(例如,您的最后一个示例是 6*100 + 0*101 + 1*102) 直到你得到一个非数字。

【讨论】:

  • 刚刚注意到...这是在 C++ 中...我在 C# 中工作。感谢您的帮助工具包,但这对我特别不起作用。任何在 C++ 中需要这个的人 - 这是你的解决方案!
  • 这个 is C# -- 将其放入文件中并编译。我没有对它进行基准测试,但如果它没有比您接受的答案更快,我会感到惊讶。我认为指针符号让你失望。
  • 我看到了指针。无论如何,感谢您对此的帮助。我很感激。
【解决方案5】:

最快的是解析字符串而不删除任何内容:

var s = "S51A24";
int m_lID = 0;

for (int i = 0; i < s.Length; i++)
{
    int d = s[i] - '0';
    if ((uint)d < 10)
        m_lID = m_lID * 10 + d;
}

Debug.Print(m_lID + ""); // 5124

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-05
    • 2010-09-06
    • 1970-01-01
    • 2016-08-11
    • 2011-03-14
    • 2011-10-03
    • 2020-12-05
    • 1970-01-01
    相关资源
    最近更新 更多