TL; DR
Используйте [.]
вместо \.
и [0-9]
вместо, \d
чтобы избежать проблем на некоторых языках (например, Java).
Спасибо безымянному за то, что изначально это признал.
Один относительно простой шаблон для сопоставления числа с плавающей запятой:
[+-]?([0-9]*[.])?[0-9]+
Это будет соответствовать:
Посмотреть рабочий пример
Если вы также хотите сопоставить 123.
(точка без десятичной части), вам понадобится немного более длинное выражение:
[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)
См . Ответ Пкеллера для более полного объяснения этого шаблона.
Если вы хотите включить недесятичные числа, например шестнадцатеричные и восьмеричные, см. Мой ответ на вопрос Как определить, является ли строка числом? .
Если вы хотите подтвердить, что ввод является числом (а не находить число во вводе), тогда вы должны окружить шаблон ^
и $
, например:
^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
Неправильные регулярные выражения
«Регулярные выражения», реализованные в большинстве современных языков, API, фреймворков, библиотек и т. Д., Основаны на концепции, разработанной в теории формального языка . Однако инженеры-программисты добавили множество расширений, которые выводят эти реализации далеко за рамки формального определения. Итак, хотя большинство обработчиков регулярных выражений похожи друг на друга, на самом деле стандарта нет. По этой причине многое зависит от того, какой язык, API, фреймворк или библиотеку вы используете.
(Между прочим, чтобы уменьшить путаницу, многие стали использовать « регулярное выражение » или « регулярное выражение » для описания этих расширенных языков сопоставления. Дополнительную информацию см. В разделе Является ли регулярное выражение таким же, как регулярное выражение? На сайте 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
потому что теперь требуется первая цифра.
На самом деле это довольно легко исправить. Вместо того, чтобы делать «десятичную» часть числа необязательной, нам нужно рассматривать ее как последовательность символов: 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
если совпадение не найдено. Также имейте в виду, что некоторые движки позволяют вам устанавливать флаги, которые изменяют определение ^
и $
, соответствуя началу / концу строки, а не началу / концу всего ввода. Обычно это не значение по умолчанию, но будьте осторожны с этими флагами.