2013-05-15 4 views
-5

Итак, у меня длинная строка цифр, но мне нужно убедиться, что у нее нет цифр, самый простой способ сделать это?C# как проверить, содержит ли длинная строка какие-либо буквы или нет?

+2

Регулярные выражения. – timmy

+1

* Скомпилированные регулярные выражения. – qJake

+8

Вам нужно начинать быть последовательным - ищете ли вы буквы или цифры? Ваше название и тело отличаются. Кроме того, если у вас есть «длинная строка цифр», но вам «нужно убедиться, что она не имеет никаких цифр», которая звучит как проблема. Внимание к деталям важно при задании вопроса. –

ответ

0

Используйте регулярные выражения:

using System.Text.RegularExpressions; 

string myString = "some long characters..."; 
if(Regex.IsMatch(myString, @"^\d+$", RegexOptions.Compiled)) 
{ 
    // String contains only numbers 
} 
if(Regex.IsMatch(myString, @"^\w+$", RegexOptions.Compiled)) 
{ 
    // String contains only letters 
} 
+0

Я не думаю, что ваше регулярное выражение делает то, что необходимо .. оно должно быть как минимум '' \\ d "' или '@" \ d "', но еще лучше должно быть как в этом ответе http: // stackoverflow.com/a/273144/863564, или он будет соответствовать любой строке, в которой есть цифра. –

+0

В то время вопрос ОП был очень расплывчатым, поэтому мой ответ соответствовал этому вопросу. Я немного исправился. – qJake

3

Вы можете использовать char.IsDigit:

var containsOnlyDigits = "007".All(char.IsDigit); // true 
+0

Он упомянул, что строка очень длинная ... LINQ крайне неэффективен в таких вещах. – qJake

+0

@SpikeX Я так не думаю .. это наверняка лучше, чем регулярное выражение, и лучше, чем пытаться его разобрать! –

+0

@SpikeX Кроме того, он быстро сработает ... –

0

Попробуйте использовать TryParse

bool longStringisInt = Int64.TryParse(longString, out number); 

Если строка (т.е. longString) не может быть преобразован в межд (т. е. имеет в нем буквы), то bool ложно, иначе это было бы правдой.

EDIT: Изменен Int64 для обеспечения более широкого охвата

+1

Не очень надежный, это могло бы потерпеть неудачу для чего-либо выше 2147483647. Если бы вы использовали этот подход, было бы лучше использовать 'Int64.TryParse'. – James

+0

@James - правда, но предположительно (возможно, ошибочно) мы имеем дело с меньшими числами. Отредактированный ответ, чтобы включить ваше предложение. –

3

Сканирование строки, проверить полукокс ... s.All(c => Char.IsDigit(c))

Enumerable.All выйдет, как только он находит нецифры characted. IsDigit очень быстро проверяет символ. Стоимость - O (N) (насколько это возможно); Конечно, это bettet, чем попытка проанализировать строку (которая не удастся, если строка действительно длинная) или использовать regexpr ...

Если вы попробуете это решение и увидите, что это слишком медленно для вас, вы можете всегда вернуться к старым добрым петлями для сканирования строки ..

foreach (char c in s) { 
    if (!Char.IsDigit(c)) 
     return false; 
} 
return true; 

или даже лучше:

for (int i = 0; i < s.Length; i++){ 
    if (!Char.IsDigit(s[i])) 
     return false; 
} 
return true; 

EDIT: эталоны, наконец!

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Text.RegularExpressions; 


namespace FindTest 
{ 
    class Program 
    { 


     const int Iterations = 1000; 

     static string TestData; 
     static Regex regex; 
     static bool ValidResult = false; 


     static void Test(Func<string, bool> function) 
     { 
      Console.Write("{0}... ", function.Method.Name); 
      Stopwatch sw = Stopwatch.StartNew(); 
      for (int i = 0; i < Iterations; i++) 
      { 
       bool result = function(TestData); 
       if (result != ValidResult) 
       { 
        throw new Exception("Bad result: " + result); 
       } 
      } 
      sw.Stop(); 
      Console.WriteLine(" {0}ms", sw.ElapsedMilliseconds); 
      GC.Collect(); 
     } 

     static void InitializeTestDataEnd(int length) 
     { 
      TestData = new string(Enumerable.Repeat('1', length - 1).ToArray()) + "A"; 
     } 

     static void InitializeTestDataStart(int length) 
     { 
      TestData = "A" + new string(Enumerable.Repeat('1', length - 1).ToArray()); 
     } 

     static void InitializeTestDataMid(int length) 
     { 
      TestData = new string(Enumerable.Repeat('1', length/2).ToArray()) + "A" + new string(Enumerable.Repeat('1', length/2 - 1).ToArray()); 
     } 

     static void InitializeTestDataPositive(int length) 
     { 
      TestData = new string(Enumerable.Repeat('1', length).ToArray()); 
     } 

     static bool LinqScan(string s) 
     { 
      return s.All(Char.IsDigit); 
     } 

     static bool ForeachScan(string s) 
     { 
      foreach (char c in s) 
      { 
       if (!Char.IsDigit(c)) 
        return false; 
      } 
      return true; 
     } 

     static bool ForScan(string s) 
     { 
      for (int i = 0; i < s.Length; i++) 
      { 
       if (!Char.IsDigit(s[i])) 
        return false; 
      } 
      return true; 
     } 

     static bool Regexp(string s) 
     { 
      // String contains numbers 
      return regex.IsMatch(s); 

      // String contains letters 
      //return Regex.IsMatch(s, "\\w", RegexOptions.Compiled); 
     } 

     static void Main(string[] args) 
     { 
      regex = new Regex(@"^\d+$", RegexOptions.Compiled); 

      Console.WriteLine("Positive (all digitis)"); 

      InitializeTestDataPositive(100000); 
      ValidResult = true;    

      Test(LinqScan); 
      Test(ForeachScan); 
      Test(ForScan); 
      Test(Regexp); 

      Console.WriteLine("Negative (char at beginning)"); 
      InitializeTestDataStart(100000); 
      ValidResult = false;    

      Test(LinqScan); 
      Test(ForeachScan); 
      Test(ForScan); 
      Test(Regexp); 

      Console.WriteLine("Negative (char at end)"); 
      InitializeTestDataEnd(100000); 
      ValidResult = false; 

      Test(LinqScan); 
      Test(ForeachScan); 
      Test(ForScan); 
      Test(Regexp); 

      Console.WriteLine("Negative (char in middle)"); 
      InitializeTestDataMid(100000); 
      ValidResult = false; 

      Test(LinqScan); 
      Test(ForeachScan); 
      Test(ForScan); 
      Test(Regexp); 

      Console.WriteLine("Done"); 
     } 
    } 
} 

Я дали положительный результат, и три негативы, 1) испытание, которое регулярное выражение является правильным, 2) ищет подтверждения подозреваемого у меня был ...

Мое мнение, что Regexp.IsMatch пришлось сканировать строку, а также, и поэтому кажется: Времена согласуются с сканирований, только 3x хуже:

Positive (all digitis) 
LinqScan... 952ms 
ForeachScan... 1043ms 
ForScan... 869ms 
Regexp... 3074ms 
Negative (char at beginning) 
LinqScan... 0ms 
ForeachScan... 0ms 
ForScan... 0ms 
Regexp... 0ms 
Negative (char at end) 
LinqScan... 921ms 
ForeachScan... 958ms 
ForScan... 867ms 
Regexp... 3986ms 
Negative (char in middle) 
LinqScan... 455ms 
ForeachScan... 476ms 
ForScan... 430ms 
Regexp... 1982ms 

Кредиты: Я заимствовал функцию тестирования от Jon тарелочкам

Выводы: s.All(Char.IsDigit) эффективен и очень прост (в конце концов, это был оригинальный вопрос). Лично я считаю, что это проще, чем регулярные выражения (мне приходилось смотреть на SO, который был правильным, поскольку я не знаком с синтаксисом C# regexp, который является стандартным, но я не знал - и предлагаемое решение было неправильным) , Итак, измеряйте и не верьте в мифы, подобные «LINQ is slow» или «RegExp медленны». В конце концов, они оба подходят для задачи (это действительно зависит от того, что вам нужно для этого), выберите тот, который вы предпочитаете.

+0

Вы, вероятно, имели в виду Char.IsDigit (c). Однако это самое быстрое решение для всех. – Candide

+0

@Candide ops, я забыл, что Char был статичным. Спасибо! Я отредактирую свой ответ –

+0

Последняя попытка: я заменил 'Char.IsDigit' на' (c < '0' || c > '9') '; это не имеет значения (IsDigit так же хорош, как и он) –

0

Вы можете использовать IndexOfAny

bool containsDigits = mystring.IndexOfAny("".ToCharArray()) != -1; 

В Linq вы бы сделать:

bool containsDigits = mystring.Any(char.IsDigit); 

Edit:

Я приуроченная это и получается решение Linq является медленнее.

Для длины строки 1,000,000 время выполнения составляет ~ 13 мс для решения linq и 1 мс для IndexOfAny.
Для длины строки 10 000 000 время выполнения для Linq все еще ~ 122 мс, тогда как IndexOfAny составляет ~ 18 мс.

+0

Отличное решение! Хотелось бы увидеть, как он сравнивается с проверкой строки и использует «IsDigit», производительность wise .. –

+0

спасибо за бенчмарк! Я ожидаю, что цикл for() будет немного быстрее, но LINQ совсем не плох. :) –

+0

@ dema80 Я стою исправлен. Я тестировал linq-решение с помощью 'All', и это неверно. Чтобы проверить, есть ли номер, вы должны использовать 'Any', как указано выше. Итак, да, linq медленнее. – Candide

Смежные вопросы