Немного о регулярных выражениях

Данную заметку меня сподвигло написать мое воспоминание о старом добром регулярном выражении которое упоминается в моей статье

Кстати вот оно

price.replace(/(d)(?=(ddd)+([^d]|$))/g, '$1 ')

Что же оно делает?

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

А теперь разберем по частям как и что именно тут происходит.

(d)(?=(ddd)+([^d]|$))

Можно разбить на несколько частей – пойдем с конца.

([^d]|$)

Эта часть означает либо любой символ кроме числа ([^d]) либо конец строки ($)
Хорошо, то есть это у нас отметка конца числа – например если в эту регулярку передать строку “12345NUMBER”, то работать она будет только с первым числом (тоже самое если перед передачей строки в регулярку мы обработаем его функцией parseInt)
Что у нас идет в скобочках дальше?

(ddd)+

На самом деле более правильная запись этой части регулярки была бы (d{3})+, но не будем придираться 😉
тут у нас идет 3 числа повторяющихся 1 и более раз.
Вот мы уже приближаемся к разгадке сути этого выражения.

У нас есть 3 числа которые должны повториться 1 и более раз и после них сразу конец строки (пока выбросим любой не цифровой символ), и получается что в следующих числах она обработает выделенные части

  • 10 – не применяется, так как цифр меньше 3х
  • 100 применяется на все число, (3 цифры повторяющиеся 1 и более раз)
  • 1000 – последние 3 нуля попадают под нашу регулярку
  • 10000000 – под регулярку попадают последние 6 нулей.

Еще ближе к разгадке – на примере сверху в последних 2х пунтках мы явно видим разряды у выделенных чисел.

Теперь перейдем к началу нашего выражения

(d)

наличие числа.
(к неведомым символам ?= я вернусь чуть позже)
Если пересмотреть примеры выше то нашему выражению соответствуют только последние 2 числа.
Первое вообще не соответствует, а у второго перед 3-мя символами нет числа.

Пока все просто – но есть небольшая несостыковочка. По логике того что я описал выше если применить полное выражение ( price.replace(/(d)(?=(ddd)+([^d]|$))/g, ‘$1 ‘) ) к числу, например, 1000 то получаем все верно –
Число (1 – $1), и после него 3 числа в количестве один и более (000 – $2) и заменяем все это на $1 ‘ 
то в итоге получим строку “1 “.
Как-то не хорошо получается.

Но я еще не все рассказал про данное выражение, и как и обещал возвращаюсь к неведомым символам ?=

Что они означают?
Такая конструкция называется “Позитивный просмотр вперед” (подробнее о просмотрах можно почитать в википедии)

А означает она то что в скобках в начале которых стоит ?= только проверяется на соответствие, но не учитывается при разборе.
Если более простым языком то мы проверяем чтобы после первой цифры (самое начало регулярного выражения – (d)) было 3 символа в количестве 1 и более, но ничего с ними не делает, и после того как применил регулярное выражение к 1 части начинает применять его ко второй, и так пока строка не закончится.

Я если честно немного сам запутался в таком объяснении 😉

Чтож, думаю что пример как работает это выражение расписанный по шагам уберет все вопросы.
Возьмем число 10 миллионов – 10000000
(в каждой итерации я буду выделять красным ту часть числа с которой выражение работает, а зеленой – часть которую оно уже обработало)

  1. 10000000
    Идем с конца, до тех пор пока количество символов будет меньше 3 но больше 1
    10 (d) – 000 (ddd) – 000 (ddd)
    Осталось у нас на руках – 10 (так как в регуярке вначале стоит всего 1 цифра то поидее должен быть 0, но для наглядности я буду применять 10)
    для нашей 10 выражение выделило область памяти ($1) а все оставшееся выражение регуялрка только проверила на соответствие, но не учла – как будто еще не дошла до него.
    И получается что в числе 10000000 у нас образовалось 2 части – 10 (уже проверенное регуляркой – $1) и 000000 (про них наше выражение, скажем так, “забыло”)
    И исходя из второй части (‘$1 ‘) мы должны в нашем числе заменить “10” на “10 “, получив тем самым “10 000000
  2. 10 000000
    На второй итерации наша регуярка работает только с шестью нулями.
    Опять идем с конца, пока количество символов будет меньше 3 но больше 1
    Ничего нет – 000 (ddd) – 000 (ddd). Выражение не подходит, значит нужно делать так
    000 (d) – 000 (ddd). Так как последние 3 нуля только проверяются на наличие, то их тоже забываем, и получается что первые три нуля это $1
    Следовательно теперь нам нужно заменить в нашей строке “000” на “000 “, получив тем самым “10 000 000”
    То что нам нужно у нас уже есть, но как вы помните регулрка “забыла” последние 3 нуля, и ей еще предстоит их обработать
  3. 10 000 000
    На третьей итерации у нас осталось следующая строка – “000”, но как вы уже поняли она не подходит под наше регулярное выражение, и оно просто пропускается.
  4. 10 000 000
    Регулярное выражение закончило свою работу и выдает нам результат – “10 000 000”

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

[Всего голосов: 1    Средний: 5/5]

Добавить комментарий

Ваш e-mail не будет опубликован.