我知道一些方法来检查字符串是否只包含数字: 正则表达式,int。解析,tryparse,循环等等。

谁能告诉我最快的方法是什么?

我只需要检查值,不需要实际解析它。

通过“数字”,我是指具体的ASCII数字:0 1 2 3 4 5 6 7 8 9。

如果字符串是数字,这个问题与Identify不同,因为这个问题不仅是关于如何识别,而且是关于识别的最快方法是什么。


当前回答

这应该可以工作:

Regex.IsMatch("124", "^[0-9]+$", RegexOptions.Compiled)

int。解析或int。TryParse并不总是有效,因为字符串可能包含int类型所能容纳的更多数字。

如果你要做这个检查不止一次,使用一个编译过的正则表达式是有用的——第一次会花费更多的时间,但之后会更快。

其他回答

我喜欢Linq,让它在第一次不匹配时退出,你可以这样做

string str = '0129834X33';
bool isAllDigits = !str.Any( ch=> ch < '0' || ch > '9' );

这应该可以工作:

Regex.IsMatch("124", "^[0-9]+$", RegexOptions.Compiled)

int。解析或int。TryParse并不总是有效,因为字符串可能包含int类型所能容纳的更多数字。

如果你要做这个检查不止一次,使用一个编译过的正则表达式是有用的——第一次会花费更多的时间,但之后会更快。

我做了一些小改变@ theecodeking的回答。

似乎;

对于int类型,最快的方法是TryParse

对于长类型最快的方法是正则表达式。

我的结果如下(打勾)

For int:

TryParse Max: 355788
IsDigitsOnly Max: 787013
Regex Max: 1297691

TryParse Avg: 186007
IsDigitsOnly Avg: 430963
Regex Avg: 464657,79

TryParse Min: 162742
IsDigitsOnly Min: 335646
Regex Min: 452121


For float :

TryParse Max : 3151995
IsDigitsOnly Max: 1392740
Regex Max : 1283451

TryParse Avg: 1391636
IsDigitsOnly Avg: 824029
Regex Avg: 501176

TryParse Min: 1187410
IsDigitsOnly Min: 706646
Regex Min: 476204

代码为long:

using System.Diagnostics;
using System.Text.RegularExpressions;

class Program
{
    private static Regex regex = new Regex("^[0-9]+$", RegexOptions.Compiled);

    static void Main(string[] args)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        watch.Stop();
        watch.Reset();
        List<TimeSpan> tryparse = new List<TimeSpan>();
        List<TimeSpan> isdigitsonly = new List<TimeSpan>();
        List<TimeSpan> regexss = new List<TimeSpan>();

        for (int say = 0; say < 1000; say++)
        { 
            float value;

            string test = Random.Shared.NextInt64(1000,long.MaxValue).ToString();
            watch.Start();
            for (int i = 0; i < 1000000; i++)
            {
                float.TryParse(test, out value);
            }
            watch.Stop();
            //Console.WriteLine("TryParse: " + watch.Elapsed);
            tryparse.Add(watch.Elapsed);

            watch.Reset();
            watch.Start();
            for (int i = 0; i < 1000000; i++)
            {
                IsDigitsOnly(test);
            }
            watch.Stop();
            //Console.WriteLine("IsDigitsOnly: " + watch.Elapsed);
            isdigitsonly.Add(watch.Elapsed);
            watch.Reset();
            watch.Start();
            for (int i = 0; i < 1000000; i++)
            {
                regex.IsMatch(test);
            }
            watch.Stop();
            regexss.Add(watch.Elapsed);
            watch.Reset();
            //   Console.WriteLine("Regex: " + watch.Elapsed);
     
            Console.Write("---------------------% " + (Convert.ToDecimal( say)/ 999 * 100).ToString("N2") + "---------------------------");
            Console.CursorLeft = 0;
        }
        Console.WriteLine();
        Console.WriteLine($"TryParse: {tryparse.Max(t => t.Ticks)}");
        Console.WriteLine($"IsDigitsOnly: {isdigitsonly.Max(t => t.Ticks)}");
        Console.WriteLine($"Regex: {regexss.Max(t => t.Ticks)}");
        Console.WriteLine();

        Console.WriteLine($"TryParse Avg: {tryparse.Average(t => t.Ticks)}");
        Console.WriteLine($"IsDigitsOnly Avg: {isdigitsonly.Average(t => t.Ticks)}");
        Console.WriteLine($"Regex Avg: {regexss.Average(t => t.Ticks)}");
        Console.WriteLine();
        Console.WriteLine($"TryParse Min: {tryparse.Min(t => t.Ticks)}");
        Console.WriteLine($"IsDigitsOnly Min: {isdigitsonly.Min(t => t.Ticks)}");
        Console.WriteLine($"Regex Min: {regexss.Min(t => t.Ticks)}");
        Console.ReadLine();
    }

    static bool IsDigitsOnly(string str)
    {
        foreach (char c in str)
        {
            if (c < '0' || c > '9')
                return false;
        }

        return true;
    }
}

如果每个char只使用一个比较,而不是foreach,可以快20%:

bool isDigits(string s) 
{ 
    if (s == null || s == "") return false; 

    for (int i = 0; i < s.Length; i++) 
        if ((s[i] ^ '0') > 9) 
            return false; 

    return true; 
}

用于测试的代码(总是配置文件,因为结果取决于硬件、版本、顺序等):

static bool isDigitsFr(string s) { if (s == null || s == "") return false; for (int i = 0; i < s.Length; i++) if (s[i] < '0' || s[i] > '9') return false; return true; }
static bool isDigitsFu(string s) { if (s == null || s == "") return false; for (int i = 0; i < s.Length; i++) if ((uint)(s[i] - '0') > 9) return false; return true; }
static bool isDigitsFx(string s) { if (s == null || s == "") return false; for (int i = 0; i < s.Length; i++) if ((s[i] ^ '0') > 9) return false; return true; }
static bool isDigitsEr(string s) { if (s == null || s == "") return false; foreach (char c in s) if (c < '0' || c > '9') return false; return true; }
static bool isDigitsEu(string s) { if (s == null || s == "") return false; foreach (char c in s) if ((uint)(c - '0') > 9) return false; return true; }
static bool isDigitsEx(string s) { if (s == null || s == "") return false; foreach (char c in s) if ((c ^ '0') > 9) return false; return true; }
static void test()
{
    var w = new Stopwatch(); bool b; var s = int.MaxValue + ""; int r = 12345678*2; var ss = new SortedSet<string>(); //s = string.Concat(Enumerable.Range(0, 127).Select(i => ((char)i ^ '0') < 10 ? 1 : 0));
    w.Restart(); for (int i = 0; i < r; i++) b = s.All(char.IsDigit); w.Stop(); ss.Add(w.Elapsed + ".All .IsDigit"); 
    w.Restart(); for (int i = 0; i < r; i++) b = s.All(c => c >= '0' && c <= '9'); w.Stop(); ss.Add(w.Elapsed + ".All <>"); 
    w.Restart(); for (int i = 0; i < r; i++) b = s.All(c => (c ^ '0') < 10); w.Stop(); ss.Add(w.Elapsed + " .All ^"); 
    w.Restart(); for (int i = 0; i < r; i++) b = isDigitsFr(s); w.Stop(); ss.Add(w.Elapsed + " for     <>");
    w.Restart(); for (int i = 0; i < r; i++) b = isDigitsFu(s); w.Stop(); ss.Add(w.Elapsed + " for     -");
    w.Restart(); for (int i = 0; i < r; i++) b = isDigitsFx(s); w.Stop(); ss.Add(w.Elapsed + " for     ^");
    w.Restart(); for (int i = 0; i < r; i++) b = isDigitsEr(s); w.Stop(); ss.Add(w.Elapsed + " foreach <>");
    w.Restart(); for (int i = 0; i < r; i++) b = isDigitsEu(s); w.Stop(); ss.Add(w.Elapsed + " foreach -");
    w.Restart(); for (int i = 0; i < r; i++) b = isDigitsEx(s); w.Stop(); ss.Add(w.Elapsed + " foreach ^");
    MessageBox.Show(string.Join("\n", ss)); return;
}

Intel i5-3470 @ 3.2GHz的结果,VS 2015 .NET 4.6.1发布模式和优化启用:

time    method          ratio
0.7776  for     ^       1.0000 
0.7984  foreach -       1.0268 
0.8066  foreach ^       1.0372 
0.8940  for     -       1.1497 
0.8976  for     <>      1.1543 
0.9456  foreach <>      1.2160 
4.4559  .All <>         5.7303 
4.7791  .All ^          6.1458 
4.8539  .All. IsDigit   6.2421 

对于任何想要使用较短方法的人,请注意

.All结果为true为空字符串,异常为空字符串 char。IsDigit对于Nd类别中的所有Unicode字符为真 int。TryParse还允许空格和符号字符

试试下面的代码:

bool isDigitsOnly(string str)
{
   try
   {
      int number = Convert.ToInt32(str);
      return true;
   }
   catch (Exception)
   {
      return false;
   }
}