Разбор числа с запятыми с помощью регулярного выражения Javascript

Я пытаюсь разобрать числа от 1 до 10 000 000, которые могут быть прямыми цифрами (например, 123456) или с разделением запятыми (1 234 567) между группами из 3 цифр. Запятые также могут быть пробелами (1 234 567) или точками (1,234,567), но используются постоянно. Я написал следующее:

<script type = "text/javascript">  
  var re = /(\d{1,3})[ |\,|\.]?(\d{3})(?:[ |\,|\.]?(\d{3}))?/i;
  function testStr(input) {
    var str = input.value;
    var newstr = str.replace(re, '[1]: $1\n[2]: $2\n[3]: $3');
    alert(newstr);
 }  
 </script>  

Это работает хорошо, за исключением того, что он также анализирует ввод, такой как 1234,567,890 или 1,234,5678. Группы из 4 последовательных цифр не допускаются. Почему это происходит? Спасибо за любую помощь.

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

Joel Cornett 16.11.2018 06:45

Я не думаю, что это работа регулярного выражения. Если вы не уверены, что число набрано без ошибок (и вы этого не сделаете), то регулярное выражение здесь - плохой выбор. Например, какое из числа 1,234.456 789 имеет каждый из разделителей, но они не согласованы. Однако он соответствует регулярному выражению. Вы может пишете регулярное выражение, чтобы отклонить это, но оно не будет красивым и простым в обслуживании, поскольку вам понадобится отдельная ветвь для каждого разделителя. Было бы проще проанализировать число и попытаться найти разделители, а затем посмотреть, соответствуют ли они в рамках других проверок.

VLAZ 16.11.2018 07:33

В качестве примечания, вы даже можете использовать библиотеку для анализа чисел за вас. Таким образом, вам не придется рвать на себе волосы, когда вы узнаете, скажем, о Индийская система написания чисел, где группировка выполняется не только по тройкам или двойкам, а по оба, и число может выглядеть как это 1,00,000,00,00,000

VLAZ 16.11.2018 07:36
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
3
75
1

Ответы 1

Один из вариантов -

^(\d{1,3})(?:([ ,.]?)(\d{3})(?:\2(\d{3}))?)?$

Идея состоит в том, чтобы использовать разделитель захватывать (если есть - если разделителя нет, то захватывается пустая строка). Затем, позже, когда в точке, где ожидается разделитель, обратная ссылка тот же разделитель, который был найден ранее, чтобы гарантировать, что все разделители одинаковы, будь то пробелы, запятые, точки или вообще ничего. Кроме того, если вам нужно проанализировать числа от 1 до 10 000 000, тогда вы должны поместить все, кроме исходного (\d{1,3}), в необязательную группу.

Обратите внимание, что в наборе символов нет необходимости экранировать запятые и точки, а | в наборе символов обозначает буквальную вертикальную черту - просто используйте вместо этого [ ,.].

Также используйте якоря ^ и $, чтобы гарантировать, что вы начинаете с самого начала строки и сопоставляете до конца строки (в противном случае принудительное сопоставление не выполняется).

https://regex101.com/r/2dFk0f/1

(\d{1,3}) - от одной до трех цифр, за которыми следует необязательная большая группа без захвата.

([ ,.]?)(\d{3})(?:\2(\d{3}))?, то есть:

([ ,.]?) - Захват используемого сепаратора

(\d{3}) - повторение трех цифр

(?:\2(\d{3})? - Если число 1 м или больше, ожидается разделитель, поэтому сделайте обратную ссылку на разделитель, который был захвачен ранее, а затем еще три цифры. (Если число меньше 1 м, эта необязательная группа не будет совпадать)

Обратная ссылка работает, но что, если вам также нужно поддерживать разделитель для десятичных дробей? $1,000,000.50 можно читать как one million dollars and 50 cents" while another culture could express this as $ 1 000 000,50` или $1.000.000,50. Вы могли бы сослаться на разделители, но я не думаю, что вы можете сказать «но десятичный разделитель такой же без обратной ссылки». И тогда вы сталкиваетесь с проблемой, скажем, с 3.500 - кто-то напечатал три с половиной с лишним нулем или триста пятьдесят? Я знаю, что OP не требует этого, но боюсь, что это не пока что.

VLAZ 16.11.2018 07:45

В самом деле, если вы добавите десятичные дроби, он станет намного более запутанным, особенно потому, что периоды могут быть разделителями тысяч.

CertainPerformance 16.11.2018 07:52

Я думаю, что проблема разделителей отвлекает нас от реальной проблемы, поэтому давайте упростим мой вопрос, разрешив только запятые и сделав их обязательными, чтобы сделать его еще проще. Итак, если я напишу / (\ d {1,3}), (\ d {3}) [, (\ d {3})]? / I; проблема по-прежнему заключается в том, что он будет анализировать группы из четырех цифр, например, 1,234,3456. Как я могу разобрать 1,234,567, но не 1,234,5678?

Leo 16.11.2018 07:54

@Leo Ответ действительно относится к этому - см. regex101.com/r/2dFk0f/2 (то же регулярное выражение, только с вашей строкой выше, добавленной к входному тексту). Идея состоит в том, чтобы, если число состоит более чем из 3 цифр, потребовать, чтобы последней трехзначной строке предшествовал разделитель (если есть какие-либо разделители вообще).

CertainPerformance 16.11.2018 07:55

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

Leo 16.11.2018 08:21

@Leo Две причины: первая заключается в том, что вам не хватает якорей начала и конца строки, как сказано в ответе (так, например, строка 1,234,5678 проходит, потому что 1,234,567 соответствует RE). Другой заключается в том, что вам нужно сделать обратную ссылку на первый разделитель, найденный там, где ожидается разделитель, иначе, например, в 1234,567, нет разделителя между 1 и 2 (разрешено, если ввод был 1234567), и есть , между 4 и 5 (разрешено, если ввод был 1,234,567), но вам нужна обратная ссылка для обеспечения согласованности (см. ответ). regex101.com/r/2dFk0f/3

CertainPerformance 16.11.2018 08:31

Другие вопросы по теме