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

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

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

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

48
задан 22 нояб. '10 в 16:53
источник поделиться
10 ответов

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

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

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

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

try {
    double.Parse(yourString, NumberStyle.Number);
}
catch(FormatException ex) {
    /* Number is not in an accepted format */
}
35
ответ дан 22 нояб. '10 в 16:55
источник

Какой номер?

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

  • Есть ли −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, 0xDEADBEEF и 0b111101101?
  • Число Inf? Является NaN?
  • Число ④②? Что насчет ?
  • Как вы относитесь к ?
  • Что делать с номерами ℵ₀ и ℵ₁? Или , и ?

Рекомендуемые шаблоны

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

  • /\D/
  • /^\d+$/
  • /^\p{Nd}+$/
  • /^\pN+$/
  • /^\p{Numeric_Value:10}$/
  • /^\P{Numeric_Value:NaN}+$/
  • /^-?\d+$/
  • /^[+-]?\d+$/
  • /^-?\d+\.?\d*$/
  • /^-?(?:\d+(?:\.\d*)?|\.\d+)$/
  • /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/
  • /^((\d)(?(?=(\d))|$)(?(?{ord$3==1+ord$2})(?1)|$))$/
  • /^(?:(?: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}))$/
  • /^(?:(?:[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}))$/
  • /^(?:(?:[+-]?)(?:[0123456789]+))$/
  • /(([+-]?)([0123456789]{1,3}(?:,?[0123456789]{3})*))/
  • /^(?:(?:[+-]?)(?:[0123456789]{1,3}(?:,?[0123456789]{3})*))$/
  • /^(?:(?i)(?:[+-]?)(?:(?=[0123456789]|[.])(?:[0123456789]*)(?:(?:[.])(?:[0123456789]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[0123456789]+))|))$/
  • /^(?:(?i)(?:[+-]?)(?:(?=[01]|[.])(?:[01]{1,3}(?:(?:[,])[01]{3})*)(?:(?:[.])(?:[01]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[01]+))|))$/
  • /^(?:(?i)(?:[+-]?)(?:(?=[0123456789ABCDEF]|[.])(?:[0123456789ABCDEF]{1,3}(?:(?:[,])[0123456789ABCDEF]{3})*)(?:(?:[.])(?:[0123456789ABCDEF]{0,}))?)(?:(?:[G])(?:(?:[+-]?)(?:[0123456789ABCDEF]+))|))$/
  • /((?i)([+-]?)((?=[0123456789]|[.])([0123456789]{1,3}(?:(?:[_,]?)[0123456789]{3})*)(?:([.])([0123456789]{0,}))?)(?:([E])(([+-]?)([0123456789]+))|))/

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

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

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

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

  • Сопоставьте, если в строке есть какие-либо цифры, включая пробелы, такие как разрывы строк.
  • Сопоставьте только в том случае, если строка содержит только цифры, за исключением, возможно, прерывания строки. Обратите внимание, что цифра определяется как имеющая свойство Десятичное число общей категории, которое доступно как \p{Nd}, \p{Decimal_Number} или \p{General_Category=Decimal_Number}. Это поворот на самом деле является лишь отражением тех кодовых пунктов, числовой тип которых - десятичный, доступный как \p{Numeric_Type=Decimal}.
  • Это то же самое, что и в большинстве языков регулярных выражений. Java здесь является исключением, поскольку он не отображает простые escape-символы charclass, такие как \w и \w, \d и \d, \s и \s, и \b или \b в соответствующее свойство Юникода. Это означает, что вы не должны использовать ни один из этих восьми односимвольных экранов для любых данных Unicode в Java, потому что они работают только на ASCII, хотя Java всегда использует символы Unicode внутри.
  • Это немного отличается от 3 в том, что он не ограничен десятичными числами, но может быть любым числом вообще; то есть, любой символ с свойством \pN, \p{Number} или \p{General_Category=Number}. К ним относятся \p{Nl} или \p{Letter_Number} для таких вещей, как римские цифры и \p{No} или \p{Other_Number} для индексированных и индексированных чисел, дробей и числа, к которым они привязаны, - например, счетные стержни.
  • Это соответствует только тем строкам, состоящим из чисел, десятичное значение которых равно 10, поэтому такие вещи, как римская цифра десять, и , , , , , и .
  • Только те строки, которые содержат символы, которым не хватает числового значения NaN; другими словами, все символы должны иметь некоторое числовое значение.
  • Совпадает только с десятичными числами, опционально с ведущим HYPHEN MINUS.
  • То же, что и 7, но теперь также работает, если знак плюс вместо минуса.
  • Ищет десятичные числа, с опциональным HYPHEN MINUS и необязательным FULL STOP плюс нулевые или более десятичные числа.
  • То же, что и 9, но не требует цифр перед точкой, если после этого есть некоторые.
  • Стандартная нотация с плавающей запятой для C и многих других языков, допускающая научную нотацию.
  • Находит числа, состоящие только из двух или более десятичных знаков любого script в порядке убывания, например 987 или 54321. Это рекурсивное регулярное выражение включает в себя выносок для кода Perl, который проверяет, имеет ли перед собой цифру приоритета значение кодовой точки, преемник текущей цифры; то есть его порядковое значение является одним большим. Это можно сделать в PCRE с использованием функции C в качестве выноски.
  • Это ищет допустимый IPv4-адрес с четырьмя десятичными числами в допустимом диапазоне, например 128.0.0.1 или 255.255.255.240, но не 999.999.999.999.
  • Это ищет допустимый MAC-адрес, поэтому шесть разделяемых двоеточиями пары из двух шестнадцатеричных цифр ASCII.
  • Это ищет целые числа в диапазоне ASCII с необязательным указателем. Это нормальный шаблон для сопоставления целых чисел ASCII.
  • Это похоже на 15, за исключением того, что для запятой требуется разделение групп из трех.
  • Это похоже на 15, за исключением того, что запятая для разделения групп теперь необязательна.
  • Это обычный шаблон для сопоставления чисел с плавающей запятой в стиле C в ASCII.
  • Это похоже на 18, но требует запятой для разделения групп из 3 и в base-2 вместо base-10.
  • Это похоже на 19, но в шестнадцатеричном формате. Обратите внимание, что необязательный показатель теперь обозначается буквой G вместо E, так как E является допустимой шестнадцатеричной цифрой.
  • Это проверяет, что строка содержит число с плавающей запятой C-стиля, но с необязательным разделителем группировки каждые три цифры либо запятой, либо подчеркиванием (LOW LINE) между ними. Он также сохраняет эту строку в группе захвата \1, предоставляя ее как $1 после успешного совпадения.

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

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

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

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{
  (?<real_number>
    # optional leading sign
    (?<real_number_sign> [+-]? )
    (?<pre_exponent_part>
        (?=                         # look ahead for what next char *will* be
            [0123456789]            #    EITHER:  an ASCII digit
          | [.]                     #    OR ELSE: a dot
        )                           # end look ahead
        (?<pre_decimal_point>
            [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 <pre_decimal_part>
         (?:                        # begin optional anon cluster
            (?<decimal_point> [.] ) # required literal dot
            (?<post_decimal_point>
                [0123456789]{0,}  )
         ) ?                        # end optional anon cluster
   )                                # end <pre_exponent_part>
   # begin anon cluster group:
   (?:
       (?<exponent_indicator> [E] ) #   base-10 exponent
       (?<exponent_number>          #   exponent number
           (?<exponent_sign>   [+-] ?         )
           (?<exponent_digits> [0123456789] + )
       )                      #   end <exponent_number>
     |                        #   or else nothing at all
   )                          # end anon cluster group
 )                            # end <real_number>
}xi;

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

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

Это еще одна вещь, чтобы сделать этот шаблон, чтобы сделать его еще более удобным. Проблема в том, что theres все еще слишком много повторений, что означает, что его слишком легко изменить в одном месте, но не в другом. Если вы делаете анализ 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)
      (?<real_number>
          (?&mantissa)
          (?&abscissa) ?

      )
      (?<abscissa>
          (?&exponent_indicator)
          (?&exponent)
      )
      (?<exponent>
          (&?sign)    ?
          (?&a_digit) +
      )
      (?<mantissa>
         # expecting either of these....
         (?= (?&a_digit)
           | (?&point)
         )
         (?&a_digit) {1,3}
         (?: (?&digit_separator) ?
             (?&a_digit) {3}
         ) *
         (?: (?&point)
             (?&a_digit) *
         ) ?
      )
      (?<point>               [.]     )
      (?<sign>                [+-]    )
      (?<digit_separator>     [_,]    )
      (?<exponent_indicator>  [Ee]    )
      (?<a_digit>             [0-9]   )
   ) # end DEFINE block
}x;

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

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

457
ответ дан 22 нояб. '10 в 18:42
источник

Попробуйте следующее:

^-?\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
9
ответ дан 22 нояб. '10 в 17:03
источник

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

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

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

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

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

С. Проведите разумную энергию Regex: используйте Tools

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

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

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

Д. Упражнение: построение регулярного выражения для спецификаций в вопросе

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

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

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

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

  • Позвольте привязать выражение между ^ и $, чтобы избежать подматричек
  • Разрешить необязательный минус: -?
  • Пусть совпадают два типа чисел по обе стороны от чередования (?: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})+)$

Смотрите демо.

6
ответ дан 24 июня '14 в 6:49
источник

Попробуйте следующее:

^-?[\d\,]+$

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

4
ответ дан 22 нояб. '10 в 16:56
источник
^-?    # 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
3
ответ дан 22 нояб. '10 в 17:06
источник
^[-+]?(\d{1,3})(,?(?1))*$

Regular expression visualization

Демоверсия Debuggex

Итак, что это?!

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

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

2
ответ дан 28 июня '14 в 13:43
источник

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

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

isADouble = myScanner.hasNextDouble()
0
ответ дан 04 марта '14 в 19:01
источник

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

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

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

-2
ответ дан 25 июня '14 в 16:01
источник

Попробуйте следующее:

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

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

-2
ответ дан 10 окт. '15 в 20:31
источник

Другие вопросы по меткам или Задайте вопрос