简体   繁体   English

检查字符串是否仅包含 C# 中的数字的最快方法

[英]Fastest way to check if string contains only digits in C#

I know a few ways of how to check if a string contains only digits:我知道如何检查字符串是否仅包含数字的几种方法:
RegEx, int.parse , tryparse , looping, etc.正则表达式、 int.parsetryparse 、循环等。

Can anyone tell me what the fastest way to check is?谁能告诉我最快的检查方法是什么?

I need only to CHECK the value, no need to actually parse it.我只需要检查值,不需要实际解析它。

By "digit" I mean specifically ASCII digits: 0 1 2 3 4 5 6 7 8 9 . “数字”是指 ASCII 数字: 0 1 2 3 4 5 6 7 8 9

This is not the same question as Identify if a string is a number , since this question is not only about how to identify, but also about what the fastest method for doing so is.这与Identify if a string is a number不是同一个问题,因为这个问题不仅关于如何识别,而且还关于最快的识别方法是什么。

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

    return true;
}

Will probably be the fastest way to do it.可能是最快的方法。

You could do this simply using LINQ:你可以简单地使用 LINQ 来做到这一点:

return str.All(char.IsDigit);

  1. .All returns true for empty strings and throws an exception for null strings. .All对空字符串返回 true,对空字符串抛出异常。
  2. char.IsDigit is true for all Unicode digit characters. char.IsDigit适用于所有 Unicode 数字字符。

Here's some benchmarks based on 1000000 parses of the same string:以下是基于 1000000 次解析相同字符串的一些基准:

Updated for release stats:更新release统计:

IsDigitsOnly: 384588
TryParse:     639583
Regex:        1329571

Here's the code, looks like IsDigitsOnly is faster:这是代码,看起来 IsDigitsOnly 更快:

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

    static void Main(string[] args)
    {
        Stopwatch watch = new Stopwatch();
        string test = int.MaxValue.ToString();
        int value;

        watch.Start();
        for(int i=0; i< 1000000; i++)
        {
            int.TryParse(test, out value);
        }
        watch.Stop();
        Console.WriteLine("TryParse: "+watch.ElapsedTicks);

        watch.Reset();
        watch.Start();
        for (int i = 0; i < 1000000; i++)
        {
            IsDigitsOnly(test);
        }
        watch.Stop();
        Console.WriteLine("IsDigitsOnly: " + watch.ElapsedTicks);

        watch.Reset();
        watch.Start();
        for (int i = 0; i < 1000000; i++)
        {
            regex.IsMatch(test);
        }
        watch.Stop();
        Console.WriteLine("Regex: " + watch.ElapsedTicks);

        Console.ReadLine();
    }

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

        return true;
    }
}

Of course it's worth noting that TryParse does allow leading/trailing whitespace as well as culture specific symbols.当然,值得注意的是 TryParse 确实允许前导/尾随空格以及特定于文化的符号。 It's also limited on length of string.它也受到字符串长度的限制。

The char already has an IsDigit(char c) which does this: char 已经有一个 IsDigit(char c) 执行此操作:

 public static bool IsDigit(char c)
    {
      if (!char.IsLatin1(c))
        return CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.DecimalDigitNumber;
      if ((int) c >= 48)
        return (int) c <= 57;
      else
        return false;
    }

You can simply do this:你可以简单地这样做:

var theString = "839278";
bool digitsOnly = theString.All(char.IsDigit);

Can be about 20% faster by using just one comparison per char and for instead of foreach :通过每个charfor而不是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; 
}

Code used for testing (always profile because the results depend on hardware, versions, order, etc.):用于测试的代码(总是配置文件,因为结果取决于硬件、版本、顺序等):

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

Results on Intel i5-3470 @ 3.2GHz, VS 2015 .NET 4.6.1 Release mode and optimizations enabled: 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 

For anyone tempted to use the shorter methods, note that对于任何想使用较短方法的人,请注意

If you are concerned about performance, use neither int.TryParse nor Regex - write your own (simple) function ( DigitsOnly or DigitsOnly2 below, but not DigitsOnly3 - LINQ seems to incur a significant overhead).如果您担心性能,请不要使用int.TryParseRegex - 编写自己的(简单)函数(下面是DigitsOnlyDigitsOnly2 ,但不是DigitsOnly3 - LINQ 似乎会产生很大的开销)。

Also, be aware that int.TryParse will fail if the string is too long to "fit" into int .另外,请注意,如果字符串太长而无法“适合” int ,则int.TryParse将失败。

This simple benchmark...这个简单的基准...

class Program {

    static bool DigitsOnly(string s) {
        int len = s.Length;
        for (int i = 0; i < len; ++i) {
            char c = s[i];
            if (c < '0' || c > '9')
                return false;
        }
        return true;
    }

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

    static bool DigitsOnly3(string s) {
        return s.All(c => c >= '0' && c <= '9');
    }

    static void Main(string[] args) {

        const string s1 = "916734184";
        const string s2 = "916734a84";

        const int iterations = 1000000;
        var sw = new Stopwatch();

        sw.Restart();
        for (int i = 0 ; i < iterations; ++i) {
            bool success = DigitsOnly(s1);
            bool failure = DigitsOnly(s2);
        }
        sw.Stop();
        Console.WriteLine(string.Format("DigitsOnly: {0}", sw.Elapsed));

        sw.Restart();
        for (int i = 0; i < iterations; ++i) {
            bool success = DigitsOnly2(s1);
            bool failure = DigitsOnly2(s2);
        }
        sw.Stop();
        Console.WriteLine(string.Format("DigitsOnly2: {0}", sw.Elapsed));

        sw.Restart();
        for (int i = 0; i < iterations; ++i) {
            bool success = DigitsOnly3(s1);
            bool failure = DigitsOnly3(s2);
        }
        sw.Stop();
        Console.WriteLine(string.Format("DigitsOnly3: {0}", sw.Elapsed));

        sw.Restart();
        for (int i = 0; i < iterations; ++i) {
            int dummy;
            bool success = int.TryParse(s1, out dummy);
            bool failure = int.TryParse(s2, out dummy);
        }
        sw.Stop();
        Console.WriteLine(string.Format("int.TryParse: {0}", sw.Elapsed));

        sw.Restart();
        var regex = new Regex("^[0-9]+$", RegexOptions.Compiled);
        for (int i = 0; i < iterations; ++i) {
            bool success = regex.IsMatch(s1);
            bool failure = regex.IsMatch(s2);
        }
        sw.Stop();
        Console.WriteLine(string.Format("Regex.IsMatch: {0}", sw.Elapsed));

    }

}

...produces the following result... ...产生以下结果...

DigitsOnly: 00:00:00.0346094
DigitsOnly2: 00:00:00.0365220
DigitsOnly3: 00:00:00.2669425
int.TryParse: 00:00:00.3405548
Regex.IsMatch: 00:00:00.7017648

Function with empty validation:具有空验证的函数:

public static bool IsDigitsOnly(string str)
  {             
        return !string.IsNullOrEmpty(str) && str.All(char.IsDigit);
  }

I like Linq and to make it exit on first mismatch you can do this我喜欢 Linq 并让它在第一次不匹配时退出,你可以这样做

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

if it is a single string :如果是单个字符串:

if (str.All(Char.IsDigit))
{
  // string contains only digits
}

if it is a list of strings :如果它是字符串列表:

if (lstStr.All(s => s.All(Char.IsDigit)))
{
  // List of strings contains only digits
}

Probably the fastest way is:可能最快的方法是:

myString.All(c => char.IsDigit(c))

Note: it will return True in case your string is empty which is incorrect (if you not considering empty as valid number/digit )注意:如果您的字符串为空且不正确,它将返回True (如果您不将空视为有效数字/数字)

You can do this in a one line LINQ statement.您可以在一行 LINQ 语句中执行此操作。 OK, I realise this is not necessarily the fastest, so doesn't technically answer the question, but it's probably the easiest to write:好的,我意识到这不一定是最快的,所以从技术上讲并不能回答这个问题,但它可能是最容易写的:

str.All(c => c >= '0' && c <= '9')

This should work:这应该有效:

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

int.Parse or int.TryParse won't always work, because the string might contain more digits that an int can hold. int.Parseint.TryParse并不总是有效,因为字符串可能包含 int 可以容纳的更多数字。

If you are going to do this check more than once it is useful to use a compiled regex - it takes more time the first time, but is much faster after that.如果您要多次执行此检查,则使用已编译的正则表达式很有用 - 第一次需要更多时间,但之后要快得多。

This might be coming super late!, but I'm sure it will help someone, as it helped me.这可能来得太晚了!但我相信它会帮助某人,因为它帮助了我。

        private static bool IsDigitsOnly(string str)
        {
            return str.All(c => c >= '0' && c <= '9');
        }

You can try using Regular Expressions by testing the input string to have only digits (0-9) by using the .IsMatch(string input, string pattern) method in C#.您可以通过使用 C# 中的.IsMatch(string input, string pattern)方法测试输入字符串是否只有数字 (0-9) 来尝试使用正则表达式。

using System;
using System.Text.RegularExpression;

public namespace MyNS
{
    public class MyClass
    {
        public void static Main(string[] args)
        {
             string input = Console.ReadLine();
             bool containsNumber = ContainsOnlyDigits(input);
        }

        private bool ContainOnlyDigits (string input)
        {
            bool containsNumbers = true;
            if (!Regex.IsMatch(input, @"/d"))
            {
                containsNumbers = false;
            }
            return containsNumbers;
        }
    }
}

Regards问候

this will work perfectly, there is many other ways but this would work这将完美地工作,还有很多其他方法,但这会工作

bool IsDigitsOnly(string str)
    {
        if (str.Length > 0)//if contains characters
        {
            foreach (char c in str)//assign character to c
            {
                if (c < '0' || c > '9')//check if its outside digit range
                    return false;
            }
        }else//empty string
        {
            return false;//empty string 
        }

        return true;//only digits
    }

Another approach!另一种方法!

string str = "12345";
bool containsOnlyDigits = true;
try { if(Convert.ToInt32(str) < 0){ containsOnlyDigits = false; } }
catch { containsOnlyDigits = false; }

Here, if the statement Convert.ToInt32(str) fails, then string does not contain digits only.在这里,如果语句Convert.ToInt32(str)失败,则字符串不只包含数字。 Another possibility is that if the string has "-12345" which gets converted to -12345 successfully, then there is a check for verifying that the number converted is not less than zero.另一种可能性是,如果字符串具有"-12345"并成功转换为-12345 ,则检查以验证转换的数字不小于零。

I did small changes @TheCodeKing's answer.我对@TheCodeKing 的回答做了一些小改动。

It seems that;看起来;

for int type fastest way is TryParse对于 int 类型最快的方法是 TryParse

for long type fastest way is Regex.对于长型,最快的方法是正则表达式。

My results below (ticks)我的结果如下(打勾)

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

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

Try this code:试试这个代码:

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

char.IsDigit(myChar)怎么样?

Very Clever and easy way to detect your string is contains only digits or not is this way:非常聪明和简单的方法来检测你的字符串是否只包含数字是这样的:

string s = "12fg";

if(s.All(char.IsDigit))
{
   return true; // contains only digits
}
else
{
   return false; // contains not only digits
}
public bool CheckforDigits(string x)
{    
    int tr;  
    return x.All(r=> int.TryParse(r.ToString(), out tr));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM