यह जांचने का सबसे तेज़ तरीका है कि क्या स्ट्रिंग में केवल अंक हैं


178

मुझे पता है कि यह कैसे जांचना है। regex, int.parse, tryparse, पाशन।

क्या कोई मुझे बता सकता है कि जांच करने का सबसे तेज़ तरीका क्या है?

आवश्यकता केवल चेक की है वास्तव में पार्स करने की कोई आवश्यकता नहीं है।

यह एक ही सवाल नहीं है: अगर एक स्ट्रिंग एक संख्या है तो मैं कैसे पहचान सकता हूं?

सवाल केवल पहचान के बारे में नहीं है। लेकिन सबसे तेज़ तरीका क्या है ।


2
w / o सिर्फ मापने से मुझे लगता है कि int.tryparse
kenny

संभवतः विधानसभा में लिखा गया एक लूप जो स्ट्रिंग से डेटा के मूल-शब्द-आकार के विखंडू को एक रजिस्टर में पढ़ता है और फिर रजिस्टर में प्रत्येक बाइट पर एक सीमा-जांच करता है।
अरथ

35
बसreturn str.All(Char.IsDigit);
मोहसिन

2
int.TryParse स्ट्रिंग केवल अंक होते हैं, तो जाँच नहीं करता है! "-13" (माइनस और स्पेस के साथ) जैसे स्ट्रिंग्स को सफलतापूर्वक पार्स किया जाएगा।
एलीश

जवाबों:


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

    return true;
}

शायद इसे करने का सबसे तेज़ तरीका होगा।


16
वहाँ भी हैchar.IsDigit()
कीथ

30
@ कीथ ने लगभग तीन सौ से अधिक पात्रों के लिए IsDigitवापसी की true। पूर्ण चौड़ाई दशमलव अंकों सहित 0123... (चीन और जापान में आम) और अन्य संस्कृतियों से अंक जैसे ০১২௧௨௩௪꘤꘥꘦꘧꘨और बहुत अधिक।
कोडइन्चौस

62
अगर किसी को परवाह है, तो यह निश्चित रूप से एक-लाइनर के लिए कम हो सकता है ->return str.All(c => c >= '0' && c <= '9');
जोन्सोपोलिस

18
आप बस यह भी कर सकते हैं return str.All(char.IsDigit);:। विधि समूहों के लिए हुर्रे!
हिममानव

11
कृपया ध्यान दें कि खाली स्ट्रिंग एक vaild संख्या नहीं है।
डैनॉन

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 पार्स को लगभग बिल्कुल समय नहीं लेना चाहिए , वैसे, उस समय के तहत जहां प्राकृतिक शोर परिणामों को निरर्थक बना देता है। मैं उपयोगी समय पाने के लिए इसे एक लाख बार पार्स करने की उम्मीद करूंगा ।
जॉन स्कीट

क्योंकि downvoted बेंचमार्क है जिस तरह से बहुत छोटा उपयोगी होने के लिए और आप का पता नहीं था कि अपने विधि भी नमूना आप कर रहे हैं परीक्षण के लिए गलत जवाब दे रहा है। नमूना स्ट्रिंग केवल अंकों से बना है, लेकिन क्योंकि यह बहुत लंबा है int, TryParse गलत है।
जॉन स्कीट

यह 1 मी के साथ बहुत करीब है। लंबाई के बारे में आह अच्छी बात है, मैं चूक गया।
theCodeKing

3
ओह, संकलन पर / ओ + के साथ, यह अब int.TryParse की तुलना में 5 गुना अधिक तेज है। बस जांच करने के लिए, आप डिबगर में नहीं चल रहे हैं?
जॉन स्कीट

59

आप बस LINQ का उपयोग करके ऐसा कर सकते हैं

return str.All(char.IsDigit);

  1. .All रिक्त स्ट्रिंग्स के लिए सही और अशक्त स्ट्रिंग्स के लिए अपवाद।
  2. char.IsDigit सभी यूनिकोड वर्णों के लिए सही है।

3
char.IsDigit विभिन्न स्थानों से कई यूनिकोड अंकों से मेल खाता है (देखें fileformat.info/info/unicode/category/Nd/list.htm )। इसके अलावा, आपका उत्तर LINQ का उपयोग करता है, इसलिए इसे करने का सबसे तेज़ तरीका होने की संभावना नहीं है। यह सबसे usecases के लिए पर्याप्त हो सकता है।
स्टीफन होल्ट

1
@StephenHolt हाँ आप सही हैं, मुझे लगता है कि जरूरी नहीं कि यह सबसे तेज हो, लेकिन यह शायद सबसे आसान है।
उदय

हां, उचित बिंदु। मैंने कुछ साल पहले भी इसी तरह का उत्तर (नीचे देखें) लिखा था, हालांकि मेरे संस्करण ने परीक्षण किया था कि क्या अन्य स्थानों से चार्ट को खत्म करने के लिए चार्ट '0' और '9' के बीच था। यह सटीक आवश्यकताओं पर निर्भर करेगा।
स्टीफन होल्ट

34

चार में पहले से ही एक IsDigit (चार सी) है जो यह करता है:

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

यदि आप यूनिकोड अंकों की जांच करने के लिए परवाह करते हैं, तो आपको एक इंट को सिर्फ इसलिए नहीं डालना चाहिए क्योंकि यह खराब कोड है, यहां तक ​​कि तेज कोड के लिए भी।
user823959

1
@ user823959: मुझे यकीन नहीं है कि आपका क्या मतलब है। Char.IsDigit mscorelib का हिस्सा है: msdn.microsoft.com/en-us/library/0t641e58.aspx
flayn

गेरहार्ड सॉरी, मेरी गलती है।
user823959

यह लूपिंग से अधिक संक्षिप्त है, लेकिन मेरी मशीन पर, एक लाख से अधिक पुनरावृत्तियों के लिए, लूप हमेशा ~ 1.5 गुना तेज होता है
सुधांशु मिश्रा

23

तेजी से प्रति सिर्फ एक तुलना का उपयोग करके 20% के बारे में हो सकता है charऔर forबजाय 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.TryParseन तो उपयोग करें और न ही Regex- अपना स्वयं का (सरल) फ़ंक्शन लिखें ( 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

मुझे लिनाक पसंद है और इसे पहले बेमेल पर बाहर निकलने के लिए आप ऐसा कर सकते हैं

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

8

संभवतः सबसे तेज़ तरीका है:

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

नोट: यह वापस आ जाएगी यह सच है के मामले में अपने स्ट्रिंग खाली है जो सही नहीं है (यदि आप वैध संख्या / अंक के रूप में खाली पर विचार नहीं)


7

यह काम करना चाहिए:

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

int.Parseया int.TryParseहमेशा काम नहीं करेगा, क्योंकि स्ट्रिंग में अधिक अंक हो सकते हैं जो एक int पकड़ सकते हैं।

यदि आप एक से अधिक बार संकलित रेक्सक्स का उपयोग करने के लिए उपयोगी है तो यह जांच करने जा रहे हैं - यह पहली बार अधिक समय लेता है, लेकिन उसके बाद बहुत तेज है।


3
यह गलत है, यह सच है अगर एक अंक भी। हालांकि संकलित विचार भयानक है।
नहुम

1
यह अब तक की सबसे धीमी विधि है, लेकिन स्ट्रिंग के अज्ञात आकार के आधार पर सबसे अच्छा समाधान है। जैसा कि उल्लेख किया गया है कि रेक्सक्स को एक ट्वीक की भी आवश्यकता है।
द कोडेकिंग

6

आप इसे एक लाइन LINQ स्टेटमेंट में कर सकते हैं। ठीक है, मुझे लगता है कि यह जरूरी सबसे तेज नहीं है, इसलिए तकनीकी रूप से इस सवाल का जवाब नहीं है, लेकिन यह शायद लिखना सबसे आसान है:

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

4
str.All(char.IsDigit)लिखना आसान है, लेकिन निश्चित रूप से आपके कोड के बराबर नहीं है।
कोडइंचौस

मैं यह परीक्षण करने की कोशिश की: pastebin.com/PuWBp9n1 रिलीज पर कोई डिबगर बेशक ... और यह तेजी से लगता है। @ जीन स्कीट क्या आप कुछ जानकारी दे सकते हैं? str.All (c => c> = '0' && c <= '9') लगता है कि IsDigit से तेज है
Nahum

1
@NahumLitvin IsDigitयूनिकोड का समर्थन करता है। इसलिए माइक्रोसॉफ्ट ने इसे लागू करते समय किस समय-मेमोरी ट्रेड-ऑफ के आधार पर चुना, चेक काफी महंगा हो सकता है। मुझे लगता है कि यह देशी कोड के लिए आगे है, कि संक्रमण काफी महंगा भी हो सकता है।
कोडइन्चौस

@CodesInChaos जब आपने कहा कि यह "मेरे कोड के बराबर नहीं है" तो मैं यह जांचने के लिए गया था कि और क्या मिलान हो सकता है, और यह पता चलता है कि अन्य स्थानों में अंक (जैसे अरबी) आपके संस्करण में मेल खाएंगे। मुझे लगता है कि यह कुछ ऐसा है जिसे ओपी को विचार करने की आवश्यकता है, चाहे ऐसे अंक मान्य हों या नहीं। Int.TryParse करते समय, मुझे लगता है कि इस तरह के पात्रों वाले तार को स्वीकार नहीं करेंगे।
स्टीफन होल्ट

LINQ कुछ भी पूरा करने का सबसे धीमा तरीका है। यदि आप कोडिंग के लिए एक कंबल नियम लागू करना चाहते हैं, तो कुछ उच्च स्तर और कार्यक्षमता प्रदान करता है, जो धीमी है।
ट्रैविसो

3

यह सुपर लेट हो सकता है!, लेकिन मुझे यकीन है कि यह किसी की मदद करेगा, क्योंकि इसने मेरी मदद की।

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

1

आप .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;
        }
    }
}

सादर


3
हाय जेसन और स्टाकेवरफ्लो में आपका स्वागत है। उत्तर देने के लिए धन्यवाद, लेकिन ध्यान दें कि प्रश्न सबसे तेज़ तरीके से था। नियमित अभिव्यक्तियाँ अपेक्षाकृत धीमी होती हैं इस पर अन्य उत्तरों में चर्चा की गई।
नाहुम

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

क्या आप बता सकते हैं कि आपका समाधान पहले से उपलब्ध कराए गए लोगों से बेहतर क्यों है?
नोएल विडमर

क्योंकि इस कोड को चलाने का समय क्रम [o (1)] दूसरों की तुलना में कम है [o (n)]
एच। बोरसिपोर

मुझे बहुत आश्चर्य Convert.ToInt32होगा अगर ओ (एन) की तुलना में तेजी से चलेगा। क्या आपके पास इस धारणा का समर्थन करने के लिए कोई सबूत है?
BDL

1
यह तेज हो सकता है अगर str वास्तव में एक संख्या है, लेकिन यह शायद Exeption के मामले में धीमा होगा। इसके अलावा यह सवाल का जवाब नहीं दे रहा है क्योंकि यह काम नहीं करेगा अगर str int.MaxValue से बड़ा है।
तोमर वोल्बर्ग

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

यद्यपि यह कोड समस्या को हल कर सकता है, आपको एक स्पष्टीकरण जोड़ना चाहिए कि यह क्यों / कैसे काम करता है। और कृपया बताएं कि आपको क्यों लगता है कि यह कोड पहले से उपलब्ध कराए गए लोगों से बेहतर है।
बीडीएल

1
इसके अलावा: आपका कोड खाली स्ट्रिंग्स के लिए सही है।
BDL


-3

बहुत ही चतुर और अपनी स्ट्रिंग का पता लगाने का आसान तरीका केवल अंक हैं या नहीं इस तरह से हैं:

string s = "12fg";

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

यदि स्थिति अनावश्यक है, तो दो रिटर्न स्टेटमेंट हैं, आप सिर्फ s.All वापस कर सकते हैं ... लेकिन अन्य मुद्दे भी हैं जैसे खाली स्ट्रिंग के साथ।
अलवरग्लारोफ़
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.