TL; DR
Використовуйте [.]замість цього, \.а не [0-9]замість цього, \dщоб уникнути проблем у деяких мовах (наприклад, Java).
Дякуємо безіменному за первісне визнання цього.
Один порівняно простий шаблон для узгодження числа з плаваючою комою
[+-]?([0-9]*[.])?[0-9]+
Це буде відповідати:
Дивіться робочий приклад
Якщо ви також хочете відповідати 123.(період без десяткової частини), вам знадобиться трохи довший вираз:
[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)
Дивіться відповідь pkeller для більш повного пояснення цієї моделі
Якщо ви хочете включити недесяткові числа, такі як шістнадцятковий і восьмеричний, дивіться мою відповідь на тему Як визначити, чи є рядок числом? .
Якщо ви хочете , щоб перевірити , що введення число (а не знайти число в межах входу), то ви повинні оточити шаблон з ^і $, наприклад , так:
^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
Нерегулярні регулярні вирази
"Регулярні вирази", реалізовані в більшості сучасних мов, API, фреймворків, бібліотек тощо, базуються на концепції, розробленій у формальній теорії мови . Однак інженери програмного забезпечення додали багато розширень, які виходять з цих реалізацій далеко за рамки формального визначення. Отже, хоча більшість двигунів регулярної експресії схожі між собою, насправді немає стандарту. З цієї причини багато що залежить від того, якою мовою, API, рамкою чи бібліотекою ви користуєтесь.
(До речі, щоб зменшити плутанину, багато хто взяв для використання " regex " або " regexp " для опису цих розширених мов відповідності. Див., Чи Regex - це те саме, що і регулярний вираз? На RexEgg.com для отримання додаткової інформації.)
Це сказало, що більшість регекс-двигунів (насправді всі вони, наскільки я знаю) погодиться \.. Швидше за все, існує проблема із втечею.
Біда з втечею
Деякі мови мають вбудовану підтримку для регулярних виразів, таких як JavaScript . Для тих мов, які цього не роблять, втеча може стати проблемою.
Це тому, що ви в основному кодуєте мовою всередині мови. Наприклад, Java використовує \як рятувальний символ у своїх рядках, тому, якщо ви хочете розмістити буквальний зворотний косий рядок у рядку, вам слід уникнути цього:
// creates a single character string: "\"
String x = "\\";
Однак, регулярні вирази також використовують \символ для втечі, тому якщо ви хочете відповідати буквальному \символу, ви повинні залишити його для двигуна regexe, а потім знову вийти з нього для 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 = "[.]";
Для регулярних виразів, \.і [.]означають одне і те ж саме. Зауважте, що це працює не в кожному випадку, як newline ( \\n), відкрита квадратна дужка ( \\[) та зворотний кут ( \\\\або [\\]).
Примітка про відповідність чисел
(Підказка: Це важче, ніж ви думаєте)
Зіставлення числа - це одна з тих речей, які, на вашу думку, можна використовувати з регулярним виразом, але насправді це досить складно. Давайте подивимось на ваш підхід, по частинах:
[-+]?
Збігайте за бажанням -або+
[0-9]*
Збіг 0 або більше послідовних цифр
\.?
Збігайте за бажанням .
[0-9]*
Збіг 0 або більше послідовних цифр
По-перше, ми можемо трохи очистити цей вираз, використовуючи скорочення класів символів для цифр (зауважте, що це також чутливе до проблеми, що згадується, згаданої вище):
[0-9] = \d
Я збираюся використовувати \dнижче, але майте на увазі, що це означає те саме, що і [0-9]. (Ну, насправді в деяких двигунах \dбудуть відповідати цифри з усіх сценаріїв, тому вони збігаються більше, ніж [0-9]будуть, але це, мабуть, не суттєво у вашому випадку.)
Тепер, якщо ви уважно подивитесь на це, ви зрозумієте, що кожна окрема частина вашого шаблону не є обов'язковою . Цей візерунок може відповідати рядку 0 довжини; рядок, що складається лише з +або -; або, рядок, що складається лише з a .. Це, мабуть, не те, що ви задумали.
Щоб виправити це, корисно почати з "прикріплення" свого регулярного виразу з мінімально необхідним рядком, ймовірно, однією цифрою:
\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якщо збіг не знайдено. Також майте на увазі, що деякі двигуни дозволяють встановлювати прапори, які змінюють визначення ^та $, узгоджуючи початок / кінець рядка, а не початок / кінець усього вводу. Зазвичай це не за замовчуванням, але слідкуйте за цими прапорами.