Ответ 1
TL; DR
Используйте [.]
Вместо \.
и [0-9]
вместо \d
чтобы избежать проблем в некоторых языках (например, Java).
Спасибо безымянному за оригинальное признание этого.
Одним из относительно простых шаблонов для сопоставления числа с плавающей запятой является
[+-]?([0-9]*[.])?[0-9]+
Это будет соответствовать:
-
123
-
123.456
-
.456
Смотрите рабочий пример
Если вы также хотите соответствовать 123.
(точка без десятичной части), тогда вам понадобится более длинное выражение:
[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)
См. Ответ Pkeller для более полного объяснения этого паттерна.
Если вы хотите включить недесятичные числа, такие как шестнадцатеричные и восьмеричные, см. Мой ответ на Как определить, является ли строка числом? ,
Если вы хотите проверить, что вход является числом (а не находить число во входе), тогда вы должны окружить шаблон ^
и $
, например, так:
^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
Нерегулярные регулярные выражения
"Регулярные выражения", как они реализованы в большинстве современных языков, API, фреймворков, библиотек и т.д., Основаны на концепции, разработанной в теории формальных языков. Тем не менее, разработчики программного обеспечения добавили много расширений, которые выводят эти реализации далеко за пределы формального определения. Таким образом, хотя большинство механизмов регулярных выражений похожи друг на друга, на самом деле стандартов нет. По этой причине многое зависит от того, какой язык, API, инфраструктуру или библиотеку вы используете.
(Кстати, чтобы помочь избежать путаницы, многие привыкли использовать " regex " или " regexp " для описания этих расширенных языков соответствия. См. Regex - это то же самое, что и регулярное выражение? На RexEgg.com для получения дополнительной информации.)
Тем не менее, большинство двигателей регулярных выражений (на самом деле, все они, насколько я знаю) будут принимать \.
, Скорее всего, существует проблема с побегом.
Проблема с побегом
Некоторые языки имеют встроенную поддержку регулярных выражений, например JavaScript. Для тех языков, которые этого не делают, побег может быть проблемой.
Это потому, что вы в основном программируете на языке внутри языка. Java, например, использует \
как escape-символ внутри строк, поэтому, если вы хотите поместить буквенный символ обратной косой черты в строку, вы должны экранировать его:
// creates a single character string: "\"
String x = "\\";
Однако регулярные выражения также используют символ \
для экранирования, поэтому, если вы хотите сопоставить буквальный символ \
, вы должны экранировать его для механизма регулярных выражений, а затем снова экранировать его для Java:
// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";
В вашем случае вы, вероятно, не избежали символа обратной косой черты на языке, на котором программируете:
// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";
Все это может сбить с толку. Если язык, с которым вы работаете, поддерживает необработанные строки, то вы должны использовать их, чтобы сократить количество обратных слешей, но не все языки поддерживают (в частности, Java). К счастью, есть альтернатива, которая будет работать иногда:
String correctPattern = "[.]";
Для двигателя регулярных выражений, \.
и [.]
означают точно то же самое. Обратите внимание, что это не работает в каждом случае, например, новая строка (\\n
), открытая квадратная скобка (\\[
) и обратная косая черта (\\\\
или [\\]
).
Примечание о совпадении чисел
(Подсказка: это сложнее, чем вы думаете)
Совпадение с числом - одна из тех вещей, которые вы считаете довольно простыми с регулярными выражениями, но на самом деле это довольно сложно. Давайте посмотрим на ваш подход, шаг за шагом:
[-+]?
Соответствует необязательному -
или +
[0-9]*
Совпадение 0 или более последовательных цифр
\.?
Соответствовать необязательно .
[0-9]*
Совпадение 0 или более последовательных цифр
Во-первых, мы можем немного очистить это выражение, используя сокращение класса символов для цифр (обратите внимание, что это также подвержено проблеме экранирования, упомянутой выше):
[0-9]
= \d
Я собираюсь использовать \d
ниже, но имейте в виду, что это означает то же самое, что и [0-9]
. (Ну, на самом деле, в некоторых движках \d
будет совпадать с цифрами из всех скриптов, поэтому он будет соответствовать больше, чем [0-9]
, но это, вероятно, не имеет значения в вашем случае.)
Теперь, если вы внимательно посмотрите на это, вы поймете, что каждая отдельная часть вашего шаблона является необязательной. Этот шаблон может соответствовать строке 0 длины; строка, состоящая только из +
или -
; или строка, состоящая только из .
, Это, вероятно, не то, что вы хотели.
Чтобы это исправить, полезно начать с "привязки" вашего регулярного выражения к минимально необходимой строке, вероятно, из одной цифры:
\d+
Теперь мы хотим добавить десятичную часть, но она не идет туда, где вы думаете:
\d+\.?\d* /* This isn't quite correct. */
Это все равно будет соответствовать значениям вроде 123.
.. Хуже того, в этом есть оттенок зла. Точка является необязательной, это означает, что у вас есть два повторяющихся класса рядом (\d+
и \d*
). На самом деле это может быть опасно, если используется неправильно, открывая вашу систему для DoS-атак.
Чтобы исправить это, вместо того, чтобы рассматривать период как необязательный, нам нужно обрабатывать его как требуется (для разделения повторяющихся классов символов) и вместо этого делать необязательным весь десятичный раздел:
\d+(\.\d+)? /* Better. But... */
Сейчас это выглядит лучше. Нам необходим промежуток между первой последовательностью цифр и второй, но есть фатальный недостаток: мы не можем сопоставить .123
потому что теперь требуется .123
цифра.
Это на самом деле довольно легко исправить. Вместо того чтобы делать десятичную часть числа необязательной, нам нужно рассматривать ее как последовательность символов: 1 или более чисел, которым может предшествовать префикс a .
этому может предшествовать 0 или более чисел:
(\d*\.)?\d+
Теперь мы просто добавляем знак:
[+-]?(\d*\.)?\d+
Конечно, эти косые черты довольно раздражают в Java, поэтому мы можем заменить их нашими классами длинных символов:
[+-]?([0-9]*[.])?[0-9]+
Сопоставление с проверкой
Это упоминалось в комментариях пару раз, поэтому я добавляю дополнение о сравнении и проверке.
Цель сопоставления состоит в том, чтобы найти некоторый контент во входных данных ("иголка в стоге сена"). Цель проверки состоит в том, чтобы убедиться, что входные данные находятся в ожидаемом формате.
Регулярные выражения, по своей природе, только соответствуют тексту. При некотором вводе они либо найдут соответствующий текст, либо не найдут. Однако, "привязывая" выражение к началу и концу ввода с помощью тегов привязки (^
и $
), мы можем гарантировать, что совпадение не будет найдено, если весь ввод не совпадает с выражением, эффективно используя регулярные выражения для проверки.
Описанное выше регулярное выражение ([+-]?([0-9]*[.])?[0-9]+
) будет соответствовать одному или нескольким числам в целевой строке. Итак, учитывая вход:
apple 1.34 pear 7.98 version 1.2.3.4
Регулярное выражение будет соответствовать 1.34
, 7.98
, 1.2
, .3
и .4
.
Чтобы проверить, что данный ввод является числом и не чем иным, как числом, "привязайте" выражение к началу и концу ввода, обернув его в теги привязки:
^[+-]?([0-9]*[.])?[0-9]+$
Это найдет совпадение, только если весь ввод представляет собой число с плавающей запятой, и не найдет совпадение, если ввод содержит дополнительные символы. Таким образом, при вводе 1.2
совпадение будет найдено, но при использовании apple 1.2 pear
совпадений не будет найдено.
Обратите внимание, что некоторые движки регулярных выражений имеют функцию validate
, isMatch
или аналогичную, которая по существу выполняет то, что я описал автоматически, возвращая true
если совпадение найдено, и false
если совпадение не найдено. Также имейте в виду, что некоторые движки позволяют вам устанавливать флаги, которые изменяют определение ^
и $
, совпадая с началом/концом строки, а не с началом/концом всего ввода. Это обычно не по умолчанию, но будьте внимательны к этим флагам.