[C#] 문자열에 숫자 만 포함되어 있는지 확인하는 가장 빠른 방법

이것을 확인하는 몇 가지 방법을 알고 있습니다. 정규식, int.parse,, tryparse반복.

누구든지 가장 빠른 확인 방법을 말해 줄 수 있습니까?

필요는 것입니다 확인하지 실제로 구문 분석에 필요합니다.

이것은 다음과 같은 질문이 아닙니다 : 문자열이 숫자인지 어떻게 알 수 있습니까?

문제는 어떻게 식별 하는가에 관한 것이 아닙니다. 가장 빠른 방법 은 무엇입니까 ?



답변

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

    return true;
}

아마 가장 빠른 방법 일 것입니다.


답변

동일한 문자열의 1000000 구문 분석을 기반으로 한 벤치 마크가 있습니다.

release통계 업데이트 :

IsDigitsOnly: 384588
TryParse:     639583
Regex:        1329571

다음은 코드입니다. 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;
    }
}

물론 TryParse는 문화적 기호뿐만 아니라 선행 / 후행 공백도 허용합니다. 또한 문자열 길이에 제한이 있습니다.


답변

LINQ를 사용하여 간단히 할 수 있습니다.

return str.All(char.IsDigit);

  1. .All 빈 문자열에 대해서는 true를 반환하고 null 문자열에 대해서는 예외를 반환합니다.
  2. char.IsDigit 모든 유니 코드 문자에 적용됩니다.

답변

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

당신은 단순히 이것을 할 수 있습니다 :

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


답변

다음 char과 같이 for대신 하나의 비교 만 사용하여 약 20 % 더 빠를 수 있습니다 foreach.

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 

더 짧은 방법을 사용하려는 유혹을 가진 사람은


답변

당신은 성능, 사용도에 대해 우려하는 경우 int.TryParseRegex– 자신의 (단순) 함수 쓰기 ( DigitsOnly또는 DigitsOnly2아래,하지만 하지 DigitsOnly3 – LINQ는 상당한 오버 헤드가 발생하는 것 같다).

또한 int.TryParse문자열이 너무 길어서에 맞지 않으면 실패 할 것 int입니다.

이 간단한 벤치 마크는 …

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

    }

}

… 다음 결과를 생성합니다 …

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


답변

빈 검증 기능 :

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