从字母数字字符串中删除字符的最快方法是什么?

What's the fastest way to remove characters from an alpha-numeric string?

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

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

我希望能够从 string 中提取数字以将它们放入 int 变量中。是否有比以下代码更快 and/or 更有效地从字符串中删除字母的方法?:(*这些字符串将在运行时动态填充 - 它们不会在构造时分配值。)

代码:

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 上找不到任何内容。非常感谢任何帮助或链接!

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

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

您可以使用 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()));
}
    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');
    }

虽然你问 "what's the fastest way to remove characters..." 你真正想说的是 "how do I create an integer by extracting only the digits from the string"。

根据这个假设,由于抛出异常,您对 Convert.ToInt32 的第一次调用在您有非数字的情况下会很慢。将其更改为

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

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

这是一个 copy/paste-able 版本:

    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) 直到你到达一个非-数字。

最快的是在不删除任何内容的情况下解析字符串:

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