Регулярное выражение для чисел с плавающей запятой

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

[-+]?[0-9]*\.?[0-9]*

Но он возвращает ошибку:

Invalid escape sequence (valid ones are  \b  \t  \n  \f  \r  \"  \'  \\ )

Насколько мне известно, нам нужно использовать escape-символ для . также. Пожалуйста, поправьте меня, где я не прав.

Ответ 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 если совпадение не найдено. Также имейте в виду, что некоторые движки позволяют вам устанавливать флаги, которые изменяют определение ^ и $, совпадая с началом/концом строки, а не с началом/концом всего ввода. Это обычно не по умолчанию, но будьте внимательны к этим флагам.

Ответ 2

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

  • Нет десятичной точки (т.е. целочисленное значение)
  • Цифры как до, так и после десятичной точки (например, 0.35, 22.165)
  • Цифры до десятичной точки (например, 0., 1234.)
  • Цифры после десятичной точки (например, .0, .5678)

В то же время вы должны убедиться, что есть где-то хотя бы одна цифра, то есть следующие недопустимы:

  • десятичная точка сама по себе
  • подписанная десятичная точка без цифр (т.е. +. или -.)
  • + или - самостоятельно
  • пустая строка

Сначала это кажется сложным, но один из способов найти вдохновение - посмотреть на источник OpenJDK для метода java.lang.Double.valueOf(String) (начать с http://hg.openjdk.java.net/jdk8/jdk8/jdk, нажмите "просмотреть", перейдите вниз /src/share/classes/java/lang/ и найдите класс Double). Длинное регулярное выражение, которое этот класс содержит, содержит различные возможности, которые OP, вероятно, не имел в виду, но игнорируя для простоты его части, которые имеют дело с NaN, бесконечностью, шестнадцатеричной нотацией и показателями, и используя \d, а не Обозначение POSIX для одной цифры, я могу уменьшить важные части регулярного выражения для числа с плавающей запятой с подписью без экспоненты:

[+-]?((\d+\.?\d*)|(\.\d+))

Я не думаю, что есть способ избежать построения (...)|(...), не допуская того, что не содержит цифр, или запрещает одну из возможностей, которая не имеет цифр до десятичной точки или без цифр после нее.

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

Ответ 3

что вам нужно:

[\-\+]?[0-9]*(\.[0-9]+)?

Я избежал знака "+" и "-", а также сгруппировал десятичную цифру со следующими цифрами, так как нечто вроде "1." не является допустимым числом.

Изменения позволят вам сопоставлять целые числа и поплавки. например:

0
+1
-2.0
2.23442

Ответ 4

Это просто: вы использовали Java, и вы должны использовать \\. вместо \. (искать экранирование символов в Java).

Ответ 5

Это работало для меня:

(?P<value>[-+]*\d+\.\d+|[-+]*\d+)

Вы также можете использовать этот (без именованного параметра):

([-+]*\d+\.\d+|[-+]*\d+)

Чтобы проверить его (например, regex101), используйте онлайн-тестер регулярных выражений

Ответ 6

[+-]?(([1-9][0-9]*)|(0))([.,][0-9]+)?

[+-]? - необязательный главный знак

(([1-9][0-9]*)|(0)) - целое число без начального нуля, включая одиночный нуль

([.,][0-9]+)? - необязательная дробная часть

Ответ 7

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

Это будет соответствовать:

  • 1.2
  • 12,3
  • 1,2
  • 12,3

Ответ 8

Я хочу сопоставить то, что большинство языков считают действительными числами (целое и число с плавающей точкой):

  • '5'/'-5'

  • '1.0'/'1.'/'.1'/'-1.'/'-.1'

  • '0.45326e+04', '666999e-05', '0.2e-3', '-33.e-1'

Заметки:

  • preceding sign of number ('-' or '+') is optional

  • '-1.' and '-.1' are valid but '.' and '-.' are invalid

  • '.1e3' is valid, but '.e3' and 'e3' are invalid

Для того, чтобы поддержать оба "1." и '.1' нам нужен оператор ИЛИ ('|'), чтобы убедиться, что мы исключаем '.' от сопоставления.

[+-]? + / - петь необязательно, так как ? означает 0 или 1 совпадений

( так как у нас есть 2 подвыражения, нам нужно поместить их в скобки

\d+([.]\d*)?(e[+-]?\d+)? Это для цифр, начинающихся с цифры

| отделяет подвыражения

[.]\d+(e[+-]?\d+)? это для чисел, начинающихся с '.'

) конец выражений

  • Для номеров, начинающихся с '.'

[.] первый символ - точка (внутри скобок, или же это символ подстановки)

\d+ одна или несколько цифр

(e[+-]?\d+)? это необязательное (0 или 1 совпадение из-за окончания '?') научное обозначение

  • Для номеров, начинающихся с цифры

\d+ одна или несколько цифр

([.]\d*)? при желании мы можем иметь символ точки ноль или более цифр после него

(e[+-]?\d+)? это необязательное научное обозначение

  • Научная нотация

e литерал, который определяет показатель

[+-]? необязательный знак экспоненты

\d+ одна или несколько цифр

Все эти вместе взятые:

[+-]?(\d+([.]\d*)?(e[+-]?\d+)?|[.]\d+(e[+-]?\d+)?)

Ответ 9

В C++ с использованием библиотеки регулярных выражений

Ответ будет примерно так:

[0-9]?([0-9]*[.])?[0-9]+

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

[+-]?([0-9]*[.])?[0-9]+

Это также отделяет обычное число или десятичное число.

Ответ 10

[+/-] [0-9]*.[0-9]+

Попробуйте это решение.

Ответ 11

для JavaScript

const test = new RegExp('^[+]?([0-9]{0,})*[.]?([0-9]{0,2})?$','g');

Который будет работать на 1,23 1234,22 0,12 12

Вы можете изменить части в {} чтобы получить разные результаты в десятичной длине и в передней части десятичной дроби. Это используется во входах для ввода числа и проверки каждого ввода при вводе только пропуска.