Соответствующие номера с регулярными выражениями – только цифры и запятые

Я не могу понять, как построить регулярное выражение для значений примера:

123,456,789 -12,34 1234 -8 

Не могли бы вы помочь мне?

Если вы хотите разрешить только цифры и запятые, ^[-,0-9]+$ является вашим регулярным выражением. Если вы также хотите разрешить пробелы, используйте ^[-,0-9 ]+$ .

Однако, если вы хотите разрешить правильные номера, лучше пойдите с чем-то вроде этого:

 ^([-+] ?)?[0-9]+(,[0-9]+)?$ 

или просто использовать парсер чисел .net (для различных NumberStyles, см. MSDN ):

 try { double.Parse(yourString, NumberStyle.Number); } catch(FormatException ex) { /* Number is not in an accepted format */ } 

Что такое номер?

У меня есть простой вопрос для вашего «простого» вопроса: что именно вы подразумеваете под «числом»?

  • Есть −0 число?
  • Как вы относитесь к √−1 ?
  • или число?
  • Является ли 186,282.42±0.02 мили / секунду одним номером – или это два или три из них?
  • 6.02e23 – число?
  • Есть ли 3.141_592_653_589 номер? Как насчет π или ? И −2π⁻³ ͥ ?
  • Сколько чисел в 0.083̄ ?
  • Сколько номеров в 128.0.0.1 ?
  • Какой номер держится? Как насчет ⚂⚃ ?
  • Имеет ли 10,5 mm одно число в нем – или у него есть два?
  • ∛8³ число – или это три из них?
  • Какое число ↀↀⅮⅭⅭⅬⅫ AUC представляет, 2762 или 2009?
  • Номера ४५६७ и ৭৮৯৮ ?
  • Что относительно 0377 , 0b111101101 и 0b111101101 ?
  • Является ли Inf номером? Является NaN ?
  • Является ④② число? Как насчет ?
  • Как вы относитесь к ?
  • Что делать ℵ₁ и ℵ₁ с цифрами? Или , и ?

Предлагаемые шаблоны

Кроме того, вы знакомы с этими шаблонами? Можете ли вы объяснить плюсы и минусы каждого?

  1. /\D/
  2. /^\d+$/
  3. /^\p{Nd}+$/
  4. /^\pN+$/
  5. /^\p{Numeric_Value:10}$/
  6. /^\P{Numeric_Value:NaN}+$/
  7. /^-?\d+$/
  8. /^[+-]?\d+$/
  9. /^-?\d+\.?\d*$/
  10. /^-?(?:\d+(?:\.\d*)?|\.\d+)$/
  11. /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/
  12. /^((\d)(?(?=(\d))|$)(?(?{ord$3==1+ord$2})(?1)|$))$/
  13. /^(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))$/
  14. /^(?:(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}))$/
  15. /^(?:(?:[+-]?)(?:[0123456789]+))$/
  16. /(([+-]?)([0123456789]{1,3}(?:,?[0123456789]{3})*))/
  17. /^(?:(?:[+-]?)(?:[0123456789]{1,3}(?:,?[0123456789]{3})*))$/
  18. /^(?:(?i)(?:[+-]?)(?:(?=[0123456789]|[.])(?:[0123456789]*)(?:(?:[.])(?:[0123456789]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[0123456789]+))|))$/
  19. /^(?:(?i)(?:[+-]?)(?:(?=[01]|[.])(?:[01]{1,3}(?:(?:[,])[01]{3})*)(?:(?:[.])(?:[01]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[01]+))|))$/
  20. /^(?:(?i)(?:[+-]?)(?:(?=[0123456789ABCDEF]|[.])(?:[0123456789ABCDEF]{1,3}(?:(?:[,])[0123456789ABCDEF]{3})*)(?:(?:[.])(?:[0123456789ABCDEF]{0,}))?)(?:(?:[G])(?:(?:[+-]?)(?:[0123456789ABCDEF]+))|))$/
  21. /((?i)([+-]?)((?=[0123456789]|[.])([0123456789]{1,3}(?:(?:[_,]?)[0123456789]{3})*)(?:([.])([0123456789]{0,}))?)(?:([E])(([+-]?)([0123456789]+))|))/

Я подозреваю, что некоторые из приведенных выше шаблонов могут удовлетворить ваши потребности. Но я не могу сказать вам, кто из них или кто-то, или, если никто не дает вам другого, потому что вы не сказали, что вы подразумеваете под «номером».

Как вы видите, существует огромное количество возможностей: на самом деле их, вероятно, стоит. ☺

Ключ к предлагаемым шаблонам

Каждое пронумерованное объяснение, приведенное ниже, описывает шаблон соответствующего пронумерованного шаблона, приведенный выше.

  1. Сопоставьте, если в строке есть какие либо разряды без цифр , включая пробелы, такие как разрывы строк.
  2. Сопоставьте только в том случае, если в строке ничего нет, кроме цифр, за исключением, возможно, отрывной строки. Обратите внимание, что цифра определяется как имеющая свойство General Decimal Number, которое доступно как \p{Nd} , \p{Decimal_Number} или \p{General_Category=Decimal_Number} . Это поворот на самом деле является лишь reflectionм тех кодовых точек, числовой тип которых – десятичный, ansible как \p{Numeric_Type=Decimal} .
  3. Это то же самое, что и в большинстве языков регулярных выражений. Java здесь является исключением, поскольку он не отображает простые escape-символы charclass, такие как \w и \W , \d и \D , \s и \S , и \b или \B в соответствующее свойство Unicode. Это означает, что вы не должны использовать ни один из этих восьми односимвольных экранов для любых данных Unicode в Java, потому что они работают только на ASCII, хотя Java всегда использует символы Unicode внутри.
  4. Это немного отличается от 3 тем, что оно не ограничивается десятичными числами, но может быть любым числом вообще; то есть любой символ с свойством \pN , \p{Number} или \p{General_Category=Number} . К ним относятся \p{Nl} или \p{Letter_Number} для таких вещей, как римские цифры и \p{No} или \p{Other_Number} для \p{Other_Number} и подстрочных чисел, дробей и номеров, связанных \p{Other_Number} – среди прочих, например, для счетных стержней.
  5. Это соответствует только тем строкам, состоящим целиком из чисел, десятичное значение которых равно 10, поэтому такие вещи, как римская цифра десять и , , , , , и .
  6. Только те строки, которые содержат символы, которым не хватает числового значения NaN; другими словами, все символы должны иметь некоторое числовое значение.
  7. Совпадает только с десятичными числами, опционально с ведущим HYPHEN MINUS.
  8. То же, что и 7, но теперь также работает, если знак плюс вместо минуса.
  9. Ищет десятичные числа, с опциональным HYPHEN MINUS и дополнительным FULL STOP плюс нулевые или более десятичные числа.
  10. То же, что и 9, но не требует цифр перед точкой, если после этого есть некоторые.
  11. Стандартная нотация с плавающей запятой для C и многих других языков, допускающая научную нотацию.
  12. Находит числа, состоящие только из двух или более десятичных знаков любого сценария в порядке убывания, например 987 или 54321. Это рекурсивное регулярное выражение включает в себя выносок для кода Perl, который проверяет, имеет ли цифра переднего плана значение кодовой точки, которое является преемником текущей цифры ; то есть его порядковое значение является одним большим. Это можно сделать в PCRE, используя функцию C в качестве выноски.
  13. Это ищет допустимый IPv4-адрес с четырьмя десятичными числами в допустимом диапазоне, например 128.0.0.1 или 255.255.255.240, но не 999.999.999.999.
  14. Это ищет допустимый MAC-адрес, поэтому шесть разделяемых двоеточиями пар из двух шестнадцатеричных цифр ASCII.
  15. Это ищет целые числа в диапазоне ASCII с дополнительным значком. Это нормальный шаблон для сопоставления целых чисел ASCII.
  16. Это похоже на 15, за исключением того, что требуется запятая для разделения групп по три.
  17. Это похоже на 15, за исключением того, что запятая для разделения групп теперь является необязательной.
  18. Это нормальный шаблон для сопоставления чисел с плавающей запятой C-стиля в ASCII.
  19. Это похоже на 18, но требуется запятая для разделения групп из 3 и в базе-2 вместо базы-10.
  20. Это похоже на 19, но в гексагоне. Обратите внимание, что необязательный показатель теперь обозначается буквой G вместо E, так как E является действительной шестнадцатеричной цифрой.
  21. Это проверяет, что строка содержит число с плавающей запятой C-стиля, но с необязательным разделителем группировки каждые три цифры либо запятой, либо подчеркиванием (LOW LINE) между ними. Он также сохраняет эту строку в группе захвата \1 , делая доступной как $1 после того, как матч будет успешным.

Источники и ремонтопригодность

Шаблоны номер 1,2,7-11 относятся к предыдущему воплощению списка часто задаваемых вопросов Perl в вопросе «Как проверить ввод?». Этот раздел был заменен предложением использовать модуль Regexp :: Common , написанный Abigail и Damian Conway . Исходные шаблоны все еще можно найти в Рецептуре 2.1 Поваренной книги Perl «Проверка правильности числа строк», решения которой могут быть найдены для головокружительного числа различных языков, включая ada, common lisp, groovy, guile, haskell, java, merd, ocaml, php, pike, python, rexx, ruby ​​и tcl в проекте PLEAC .

Образец 12 можно было бы более parsingчиво переписать

 m{ ^ ( ( \d ) (?(?= ( \d ) ) | $ ) (?(?{ ord $3 == 1 + ord $2 }) (?1) | $ ) ) $ }x 

Он использует рекурсию regex , которая находится во многих моделях шаблонов, включая Perl и все языки, созданные на основе PCRE. Но он также использует встроенную идентификацию кода как тест ее второго условного шаблона; Насколько мне известно, выноски кода доступны только в Perl и PCRE.

Шаблоны 13-21 были получены из вышеупомянутого модуля Regexp :: Common. Обратите внимание, что для краткости все они написаны без пробелов и комментариев, которые вы обязательно захотите в производственном коде. Вот как это может выглядеть в режиме /x :

 $real_rx = qr{ ( # start $1 to hold entire pattern ( [+-]? ) # optional leading sign, captured into $2 ( # start $3 (?= # look ahead for what next char *will* be [0123456789] # EITHER: an ASCII digit | [.] # OR ELSE: a dot ) # end look ahead ( # start $4 [0123456789]{1,3} # 1-3 ASCII digits to start the number (?: # then optionally followed by (?: [_,]? ) # an optional grouping separator of comma or underscore [0123456789]{3} # followed by exactly three ASCII digits ) * # repeated any number of times ) # end $4 (?: # begin optional cluster ( [.] ) # required literal dot in $5 ( [0123456789]{0,} ) # then optional ASCII digits in $6 ) ? # end optional cluster ) # end $3 (?: # begin cluster group ( [E] ) # base-10 exponent into $7 ( # exponent number into $8 ( [+-] ? ) # optional sign for exponent into $9 ( [0123456789] + ) # one or more ASCII digits into $10 ) # end $8 | # or else nothing at all ) # end cluster group ) }xi; # end $1 and whole pattern, enabling /x and /i modes 

С точки зрения программного обеспечения все еще есть несколько проблем со стилем, используемым в версии режима /x непосредственно выше. Во-первых, существует много повторений кода, где вы видите то же самое [0123456789] ; что произойдет, если одна из этих последовательностей случайно выйдет из цифры? Во-вторых, вы полагаетесь на позиционные параметры, которые вы должны учитывать. Это означает, что вы можете написать что-то вроде:

 ( $real_number, # $1 $real_number_sign, # $2 $pre_exponent_part, # $3 $pre_decimal_point, # $4 $decimal_point, # $5 $post_decimal_point, # $6 $exponent_indicator, # $7 $exponent_number, # $8 $exponent_sign, # $9 $exponent_digits, # $10 ) = ($string =~ /$real_rx/); 

который откровенно отвратительный! Легко получить нумерацию неправильно, трудно вспомнить, какие символические имена идут туда и утомительно писать, особенно если вам не нужны все эти штуки. Переписывая это, чтобы использовать именованные группы вместо просто пронумерованных. Опять же, я буду использовать синтаксис Perl для переменных, но содержимое шаблона должно работать везде, где поддерживаются именованные группы.

 use 5.010; # Perl got named patterns in 5.10 $real_rx = qr{ (? # optional leading sign (? [+-]? ) (? (?= # look ahead for what next char *will* be [0123456789] # EITHER: an ASCII digit | [.] # OR ELSE: a dot ) # end look ahead (? [0123456789]{1,3} # 1-3 ASCII digits to start the number (?: # then optionally followed by (?: [_,]? ) # an optional grouping separator of comma or underscore [0123456789]{3} # followed by exactly three ASCII digits ) * # repeated any number of times ) # end  (?: # begin optional anon cluster (? [.] ) # required literal dot (? [0123456789]{0,} ) ) ? # end optional anon cluster ) # end  # begin anon cluster group: (?: (? [E] ) # base-10 exponent (? # exponent number (? [+-] ? ) (? [0123456789] + ) ) # end  | # or else nothing at all ) # end anon cluster group ) # end  }xi; 

Теперь названы абстракции, что помогает. Вы можете вытащить группы по имени, и вам нужны только те, о которых вы заботитесь. Например:

 if ($string =~ /$real_rx/) { ($pre_exponent, $exponent_number) = @+{ qw< pre_exponent exponent_number > }; } 

Есть еще одна вещь, чтобы сделать этот шаблон, чтобы сделать его еще более удобным. Проблема в том, что все еще слишком много повторений, что означает, что его слишком легко изменить в одном месте, но не в другом. Если вы делаете анализ McCabe, вы бы сказали, что его метрика сложности слишком высока. Большинство из нас просто сказали, что это слишком отступы. Это затрудняет работу. Чтобы исправить все эти вещи, нам нужен «грамматический паттерн», один с блоком определения для создания именованных абстракций, которые затем мы будем рассматривать как вызов подпрограммы позже в матче.

 use 5.010; # Perl first got regex subs in v5.10 $real__rx = qr{ ^ # anchor to front (?&real_number) # call &real_number regex sub $ # either at end or before final newline ################################################## # the rest is definition only; think of ## # each named buffer as declaring a subroutine ## # by that name ## ################################################## (?(DEFINE) (? (?&mantissa) (?&abscissa) ? ) (? (?&exponent_indicator) (?&exponent) ) (? (&?sign) ? (?&a_digit) + ) (? # expecting either of these.... (?= (?&a_digit) | (?&point) ) (?&a_digit) {1,3} (?: (?&digit_separator) ? (?&a_digit) {3} ) * (?: (?&point) (?&a_digit) * ) ? ) (? [.] ) (? [+-] ) (? [_,] ) (? [Ee] ) (? [0-9] ) ) # end DEFINE block }x; 

Посмотрите, насколько безумно лучше грамматический рисунок, чем исходный штриховой узор? Также гораздо проще получить синтаксис правильно: я набрал это без одной синтаксической ошибки регулярного выражения, которая требует исправления. (Хорошо, я набрал все остальные без каких-либо синтаксических ошибок, но я делал это некоторое время. 🙂

Грамматические модели выглядят скорее как BNF, чем уродливые старые регулярные выражения, которые люди стали ненавидеть. Их гораздо легче читать, писать и поддерживать. Так что давайте не будем иметь более уродливые шаблоны, хорошо?

Попробуй это:

 ^-?\d{1,3}(,\d{3})*(\.\d\d)?$|^\.\d\d$ 

Позволяет:

 1 12 .99 12.34 -18.34 12,345.67 999,999,999,999,999.99 

Поскольку этот вопрос был вновь открыт четыре года спустя, я хотел бы предложить другое занятие. Поскольку кто-то тратит много времени на работу с регулярным выражением, мой взгляд таков:

A. Если возможно, не используйте регулярное выражение для проверки номеров

Если это вообще возможно, используйте свой язык. Могут быть функции, которые помогут вам определить, является ли значение, содержащееся в строке, допустимым числом. При этом, если вы принимаете различные форматы (запятые и т. Д.), У вас может не быть выбора.

B. Не пишите регулярное выражение для проверки диапазона номеров

  • Написание регулярного выражения в соответствии с числом в заданном диапазоне сложно. Вы можете сделать ошибку, даже написав регулярное выражение, чтобы соответствовать числу от 1 до 10 .
  • Когда у вас есть регулярное выражение для диапазона чисел, его трудно отлаживать. Во-первых, это ужасно смотреть. Во-вторых, как вы можете быть уверены, что он соответствует всем желаемым значениям без соответствия любым из значений, которые вы не хотите? Честно говоря, если вы сами, без сверстников, оглядывающих ваше плечо, вы не можете. Лучшая технология отладки заключается в том, чтобы выводить целый ряд чисел программно и проверять их на регулярное выражение.
  • К счастью, есть инструменты для автоматического создания регулярного выражения для диапазона чисел.

C. Проведите свою энергию регулярного выражения с умом: используйте инструменты

  • Соответствующие числа в заданном диапазоне – проблема, которая была решена. Вам не нужно пытаться изобретать велосипед. Это проблема, которая может быть решена механически, программой, таким образом, которая гарантированно будет безошибочной. Воспользуйтесь этой бесплатной поездкой.
  • Решение регулярного выражения с несколькими номерами может быть интересным для учебных целей пару раз. Помимо этого, если у вас есть энергия, чтобы вкладывать средства в развитие навыков регулярного выражения, потратьте его на что-то полезное, например, углубите понимание жадности регулярных выражений , читаете в регулярном выражении Юникода , играете с совпадением нулевой ширины или рекурсией, читаете часто задаваемые вопросы SO regex и обнаруживать аккуратные трюки, например, как исключить определенные шаблоны из соответствия регулярному выражению … или читать classику, такую ​​как регулярные выражения для регулярного выражения, 3-е издание или «Поваренная книга регулярных выражений», 2-е изд .

Для инструментов вы можете использовать:

  • В сети: Regex_for_range
  • Offline: единственное, что я знаю, это RegexMagic (не бесплатно) гуру regex Jan Goyvaerts. Это его новый продукт regex, и, как я помню, у него есть большой выбор опций для генерации чисел в заданном диапазоне, среди других функций.
  • Если условия слишком сложны, автогенерируйте два диапазона … затем присоедините их к оператору чередования |

D. Упражнение: создание регулярного выражения для характеристик в вопросе

Эти спецификации довольно широкие … но не обязательно расплывчатые. Давайте снова посмотрим на образцы:

 123,456,789 -12,34 1234 -8 

Как соотносятся первые два значения? Во-первых, запятая соответствует группам из трех. Во втором случае он, вероятно, соответствует десятичной точке в формате номера в формате континентального европейского стиля. Это не означает, что мы должны допускать цифры везде, как в 1,2,3,44 . Точно так же мы не должны быть ограничительными. Регулярное выражение в принятом ответе, например, не будет соответствовать одному из требований, 123,456,789 (см. Демо ).

Как мы создаем наше регулярное выражение для соответствия спецификациям?

  • Давайте привяжем выражение между ^ и $ чтобы избежать подматричек
  • Разрешите дополнительный минус: -?
  • Давайте сопоставим два типа чисел по обе стороны от чередования (?:this|that) :
  • Слева цифра европейского стиля с дополнительной запятой для десятичной части: [1-9][0-9]*(?:,[0-9]+)?
  • Справа число с тысячами разделителей: [1-9][0-9]{1,2}(?:,[0-9]{3})+

Полное регулярное выражение:

 ^-?(?:[1-9][0-9]*(?:,[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$ 

См. Демонстрацию .

Это регулярное выражение не позволяет номера в европейском стиле, начиная с 0 , например 0,12 . Это особенность, а не ошибка. Чтобы соответствовать этим, небольшая настройка сделает следующее:

 ^-?(?:(?:0|[1-9][0-9]*)(?:,[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$ 

См. Демонстрацию .

Попробуй это:

 ^-?[\d\,]+$ 

Это позволит опционально - как первый символ, а затем любую комбинацию запятых и цифр.

 ^-? # start of line, optional - (\d+ # any number of digits |(\d{1,3}(,\d{3})*)) # or digits followed by , and three digits ((,|\.)\d+)? # optional comma or period decimal point and more digits $ # end of line 
 ^[-+]?(\d{1,3})(,?(?1))*$ 

Визуализация регулярных выражений

Демоверсия Debuggex

Так что же это ?!

  • ^ отмечает начало строки
  • [-+]? позволяет минус или плюс сразу после начала строки
  • (\d{1,3}) соответствует по крайней мере одной и нескольким ( {1,3} ) цифрам ( \d – обычно [0-9] ) в строке и группирует их (скобки (...) строит группа) в качестве первой группы
  • (,?(?1))* ok … давайте сломаем это
    • (...) строит другую группу ( не так важно )
    • ,? соответствует запятой (если существует) сразу после первой последовательности цифр
    • (?1) снова совпадает с шаблоном первой группы (помните (\d{1,3}) ); в словах: в этот момент выражение соответствует знаку (плюс / минус / нет), за которым следует последовательность цифр, за которыми следует запятая, за которой следует еще одна последовательность цифр.
    • (,?(?1))* , * повторяет вторую часть (запятую и последовательность) как можно чаще
  • $ окончательно совпадает с концом строки

преимущество таких выражений состоит в том, чтобы избежать повторения одного и того же шаблона в вашем выражении снова и снова … ну, недостатком иногда является сложность: – /

В java вы можете использовать java.util.Scanner с useLocale метода useLocale

 Scanner myScanner = new Scanner(input).useLocale( myLocale) isADouble = myScanner.hasNextDouble() 

Для примеров:

  ^(-)?([,0-9])+$ 

Он должен работать. Внедрите его в зависимости от того, какой язык вам нужен.

Попробуй это:

  boxValue = boxValue.replace(/[^0-9\.\,]/g, ""); 

Этот RegEx будет соответствовать только цифрам, точкам и запятым.

Давайте будем гением компьютера.