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


178

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

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

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

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

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


2
int.tryparse
kenny

아마도 어셈블리에서 작성된 루프는 문자열에서 기본 단어 크기의 데이터 청크를 레지스터로 읽은 다음 레지스터의 각 바이트에서 범위 검사를 수행합니다.
aroth

35
간단히return str.All(Char.IsDigit);
Mohsen

2
int.TryParse는 문자열에 숫자 만 포함되어 있는지 확인하지 않습니다! "-13"(빼기 및 공백 포함)과 같은 문자열은 구문 분석됩니다.
aleyush

답변:


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

    return true;
}

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


16
또한char.IsDigit()
키이스

30
@Keith IsDigittrue약 3 백 자 이상의 문자를 반환 합니다. 전각 10 진수 0123(중국과 일본에서 일반적)와 다른 문화권의 숫자 ০১২௧௨௩௪꘤꘥꘦꘧꘨등을 포함합니다.
코드 InChaos

62
누군가 관심이 있다면, 이것은 확실히 한 라이너로 줄어들 수 있습니다->return str.All(c => c >= '0' && c <= '9');
Jonesopolis

18
당신은 단순히 이것을 할 수도 있습니다 : return str.All(char.IsDigit);. 분석법 그룹을위한 만세!
Icemanind

11
빈 문자열은 유효한 숫자가 아닙니다.
Danon

64

동일한 문자열의 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는 문화적 기호뿐만 아니라 선행 / 후행 공백도 허용합니다. 또한 문자열 길이에 제한이 있습니다.


숫자를 파싱하려면 기본 변환을 수행 할 때 각 숫자를 확인하는 것보다 시간이 많이 걸립니다.

1
동일한 문자열의 1000 개 파싱 거의해야 잘 자연 잡음이 결과 미미를 렌더링하는 시간에 따라, 그런데, 전혀 시간을. 유용한 타이밍을 얻으려면 백만 번 구문 분석해야합니다 .
Jon Skeet

때문에을 downvoted 벤치 마크는 방법이 유용 할 너무 짧은 하고 당신은 당신의 방법도 샘플 당신에게있는 거 테스트를 위해 잘못된 대답을주고 있음을 발견하지 않았다. 샘플 문자열 자릿수로만 구성되어 있지만에는 너무 길기 때문에 intTryParse가 false를 반환합니다.
Jon Skeet

1m에 훨씬 가깝습니다. 아 길이에 대한 좋은 지적, 나는 그것을 그리워했다.
TheCodeKing

3
/ o +를 컴파일하면 int.TryParse보다 5 배 이상 빠릅니다. 확인하기 위해 디버거에서 실행되고 있지 않습니까?
Jon Skeet

59

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

return str.All(char.IsDigit);

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

3
char.IsDigit는 다양한 로케일의 수많은 유니 코드 숫자와 일치합니다 ( fileformat.info/info/unicode/category/Nd/list.htm 참조 ). 또한 귀하의 답변은 LINQ를 사용하므로 가장 빠른 방법은 아닙니다. 그래도 대부분의 유스 케이스에 충분할 수 있습니다.
Stephen Holt

1
@StephenHolt 네, 그렇습니다. 필자가 이것이 가장 빠른 것은 아니라는 것을 알고 있지만 아마도 가장 쓰는 것이 가장 쉽습니다.
Uday

그렇습니다. 몇 년 전에 비슷한 대답 (아래 참조)을 작성했지만 내 버전은 다른 로케일에서 문자를 제거하기 위해 문자가 '0'과 '9'사이인지 테스트했습니다. 정확한 요구 사항에 따라 다릅니다.
Stephen Holt

34

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

유니 코드 숫자를 확인하려는 경우 코드가 빠르더라도 나쁜 코드이기 때문에 문자를 int로 캐스팅해서는 안됩니다.
user823959

1
@ user823959 : 무슨 말인지 잘 모르겠습니다. Char.IsDigit는 mscorelib의 일부입니다. msdn.microsoft.com/en-us/library/0t641e58.aspx
flayn

게르하르트 미안, 내 실수.
user823959

이것은 루핑보다 간결하지만, 내 컴퓨터에서 백만 회 이상 반복하면 for 루프는 항상 ~ 1.5 배 빠릅니다.
Sudhanshu Mishra

23

다음 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 

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


14

당신은 성능, 사용도에 대해 우려하는 경우 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

11

빈 검증 기능 :

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

10

나는 Linq를 좋아하고 첫 번째 불일치로 종료되도록 할 수 있습니다.

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

8

아마도 가장 빠른 방법은 다음과 같습니다.

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

참고 : 문자열이 비어있는 경우 True 를 반환 합니다 (공백을 유효한 숫자 / 숫자로 간주하지 않는 경우)


7

이것은 작동해야합니다 :

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

int.Parse또는 int.TryParse문자열이 INT가 보유 할 수 이상의 숫자를 포함 할 수 있기 때문에 항상 작동하지 않습니다.

이 검사를 두 번 이상 수행하려는 경우 컴파일 된 정규식을 사용하는 것이 유용합니다. 처음에는 시간이 더 걸리지 만 그 이후에는 훨씬 빠릅니다.


3
이것은 틀 렸으며, 한자리수라도 있다면 참을 반환합니다. 칭찬 된 아이디어는 굉장하지만.
Nahum

1
이것은 지금까지 가장 느린 방법이지만 알 수없는 크기의 문자열을 기반으로하는 최상의 솔루션입니다. 언급했듯이 정규 표현식도 조정해야합니다.
TheCodeKing

6

한 줄의 LINQ 문에서이 작업을 수행 할 수 있습니다. OK, 이것이 이것이 가장 빠른 것은 아니라는 것을 알고 기술적으로 질문에 대답하지는 않지만 아마도 가장 작성하기 쉽습니다.

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

4
str.All(char.IsDigit)작성하기는 쉽지만 물론 코드와 동일하지는 않습니다.
코드 InChaos

나는 이것을 테스트하려고 시도했다 : 물론 릴리즈 디버거가없는 pastebin.com/PuWBp9n1 ... WAYYYY가 더 빠르다. @ Jon Skeet 통찰력을 제공 할 수 있습니까? str.All (c => c> = '0'&& c <= '9')는 IsDigit
Nahum

1
@NahumLitvin IsDigit은 유니 코드를 지원합니다. 따라서 Microsoft가 구현할 때 선택한 시간 메모리 상충 관계에 따라 수표가 상당히 비쌀 수 있습니다. 네이티브 코드로 전달한다고 가정하면 전환 비용도 상당히 많이들 수 있습니다.
코드 InChaos

@CodesInChaos "내 코드와 동일하지 않다"고 말했을 때 다른 것이 일치하는지 확인하고 다른 로케일 (예 : 아랍어)의 숫자가 버전과 일치하는 것으로 나타났습니다. 그러한 숫자가 유효한지 여부에 관계없이 OP가 고려해야 할 사항이라고 생각합니다. int.TryParse를 수행 할 때 그러한 문자가 포함 된 문자열을 허용하지 않을 것이라고 생각합니다.
Stephen Holt

LINQ는 가장 느린 방법입니다. 코딩에 블랭킷 규칙을 적용하려면 무언가 높은 수준의 기능을 제공할수록 느리다고 가정하십시오.
TravisO

3

이것은 매우 늦게 올 수 있습니다! 그러나 그것이 나를 도우면서 누군가를 도울 것이라고 확신합니다.

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

1

.IsMatch(string input, string pattern)C # 의 방법 을 사용하여 숫자 (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;
        }
    }
}

문안 인사


3
안녕하세요 Jason과 Stackoverflow에 오신 것을 환영합니다. 답변 해 주셔서 감사하지만 질문은 가장 빠른 방법에 관한 것입니다. 정규식은 상대적으로 느립니다. 이것은 다른 답변에서 논의되었습니다.
Nahum

1

이것은 완벽하게 작동하며 다른 많은 방법이 있지만 작동합니다.

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
    }

0

이 코드를 사용해보십시오 :

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

솔루션이 이미 제공된 솔루션보다 나은 이유를 설명 할 수 있습니까?
노엘 Widmer

이 코드를 실행하는 시간 순서가 [o (1)] 다른 것보다 적기 때문에 [o (n)]
H. Borsipour

Convert.ToInt32o (n)보다 빠르게 실행 되면 매우 놀랐습니다 . 이 가정을 뒷받침 할 증거가 있습니까?
BDL

1
str이 실제로 숫자이면 더 빠를 수 있지만 Exeption의 경우 속도가 느려질 수 있습니다. 또한 str이 int.MaxValue보다 큰 숫자이면 작동하지 않기 때문에 질문에 대답하지 않습니다.
Tomer Wolberg

-2
public bool CheckforDigits(string x)
{    
    int tr;  
    return x.All(r=> int.TryParse(r.ToString(), out tr));
}

이 코드로 문제를 해결할 수 있지만 그 이유 / 어떻게 작동하는지 설명을 추가해야합니다. 이 코드가 이미 제공된 코드보다 낫다고 생각하는 이유를 설명하십시오.
BDL

1
또한 : 코드는 빈 문자열에 대해 True를 반환합니다.
BDL


-3

문자열을 감지하는 매우 영리하고 쉬운 방법은 숫자 만 포함하거나 포함하지 않는 것입니다.

string s = "12fg";

if(s.All(char.IsDigit))
{
   return true; // contains only digits
}
else
{
   return false; // contains not only digits
}

if 조건이 필요하지 않으므로 두 개의 return 문이 있으므로 s.All을 반환 할 수 있습니다 ...하지만 빈 문자열과 같은 다른 문제가 있습니다.
alvarlagerlof
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.