2013-05-30 2 views
12

Я искал короткий код, который может помещать запятые в набор цифр, пока я не достиг this site.Regex читает справа налево

Код:

function addCommas(nStr) 
{ 
    nStr += ''; 
    x = nStr.split('.'); 
    x1 = x[0]; 
    x2 = x.length > 1 ? '.' + x[1] : ''; 
    var rgx = /(\d+)(\d{3})/; 
    while (rgx.test(x1)) { 
     x1 = x1.replace(rgx, '$1' + ',' + '$2'); 
    } 
    return x1 + x2; 
} 

работает действительно здорово. Имея этот пример набора номера:

addCommas('83475934.89'); 

вернется "83,475,934.89", но когда я прочитал код, я ожидаю, что вернуть 8,3,4,7,5,934.89 но это сайты объясняет, что

\d+ в сочетании с \d{3} будет соответствовать группе из 3 номеров предшествует любое количество чисел. Это приводит к тому, что поиск заменяется справа налево.

И я так запутался. Как этот код читается справа налево? Кроме того, что означает $1 и $2?

+1

'$ 1' и' $ 2' представляют группы захвата – smerny

+3

Это не _read_ справа налево, оно _replaces_ справа налево. Вроде. Обратите внимание, что вы можете сделать функцию еще короче - очень незначительное изменение в регулярном выражении устраняет необходимость делать 'split()' в десятичной точке, сохраняя три строки кода: http://jsfiddle.net/TqCRh/ – nnnnnn

+0

@nnnnnn Хорошая добыча! –

ответ

5

Он совпадает справа налево, потому что он использует жадный шаблону. Это означает, что он сначала находит все цифры (\ d +), , затем пытается найти \ d {3}. Например, в номере 2421567.56 он сначала будет соответствовать цифрам до «.». - 2431567 - затем работает назад, чтобы сопоставить следующие 3 цифры (567) в следующей части регулярного выражения. Он делает это в цикле, добавляя запятую между переменными $ 1 и $ 2.

$ представляют собой соответствующие группы, сформированные в регулярном выражении с круглыми скобками, например. (\ d +) = $ 1 и (\ d {3}) = $ 2. Таким образом, он может легко добавлять символы между ними.

В следующей итерации жадное совпадение останавливается только на вновь созданной запятой, и оно продолжается до тех пор, пока оно не будет соответствовать> 3 цифры.

+0

+1 Я люблю ваше объяснение. Теперь это ясно. – fiberOptics

3

Это объяснение было дальше на той же странице

Код Объяснение: Код начинается деления строки на две части (НСТР и nStrEnd), если существует десятичное. Для добавления запятой используется регулярное выражение . 0Str. . Затем добавляется nStrEnd. Если строка не имеет nStrEnd временно удалены, то регулярное выражение будет форматировать 10,0004 как 10.0,004

Regular Expression Объяснение: \ д + в сочетании с \ d {3} будет соответствовать группе из трех чисел, которым предшествует любое количество цифр. Это приманивает поиск к замене справа налево.

$1 и $2 получены от группового совпадения от регулярного выражения. Вы можете прочитать больше на эту тему по адресу Regex Tutorial.

+0

+1 для совместного использования link как мне :) хорошо, что и, знаете, для хорошего ответа (используя собственный источник OP)! –

2

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

14

Это не фактически чтение справа налево. Что действительно происходит, так это то, что он неоднократно применяет шаблон (\d+)(\d{3}) (через цикл while) и заменяет его до тех пор, пока он больше не будет соответствовать шаблону.Другими словами:

Итерация 1:

x1 = 83475934.89 
x1.replace((\d+)(\d{3}), '$1' + ',' + '$2'); 
x1 = 83475,934.89 

Итерация 2:

x1 = 83475,934.89 
x1.replace((\d+)(\d{3}), '$1' + ',' + '$2'); 
x1 = 83,475,934.89 

Итерация 3:

x1 = 83,475,934.89 
x1.replace((\d+)(\d{3}), '$1' + ',' + '$2'); 
// no match; end loop 

Редактировать:

Плюс, что означает $ 1 и $ 2?

Тезисы ссылаются на соответствующие группы (\d+) и (\d{3}) соответственно.

Вот отличный справочник для обучения, как регулярные выражения на самом деле работает:
http://www.regular-expressions.info/quickstart.html

+0

Лучший способ объяснить это. – crush

+0

В Iteration 1 можно ожидать, что результат будет '834,75934.89'? – fiberOptics

+0

@fiberOptic № 834,75934.89 является '(\ d +) (\ d {5})'. – JJJ

1

Я написал регулярное выражение, которое делает то же самое в один проход:

/(?!\b)(\d{3}(?=(\d{3})*\b))/g 

Попробуйте это, например, с различным числом в начале:

var num = '123456789'; 
 

 
for(var i = 1; i <= num.length; i++) 
 
{ 
 
    console.log(num.slice(0, -i).replace(/(?!\b)(\d{3}(?=(\d{3})*\b))/g, ',$1')); 
 
}


Я попытаюсь сломать его здесь:

Игнорировать этот бит на данный момент - я вернусь к этому.

(?! \ Б) (\ d {3} (? = (\ D {3}) * \ б))


Он по-прежнему читает слева направо пытаясь захватить блоки из 3 цифр. Вот группа захвата.

(?! \ Б) (\ d {3} (? = (\ D {3}) * \ б) )


Однако внутри захвата group, он использует lookahead.

(?! \ Б) (\ d {3} (? = (\ d {3}) * \ б ))


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

(?! \ Б) (\ d {3} (? = (\ d {3}) * \ б))


У меня проблема была в том, что JavaScript не поддерживает атомные образы, поэтому, когда число имеет кратное 3 знакам, оно соответствовало первым 3 цифрам и помещало запятую в самом начале номера.
Вы не можете сопоставить символ перед 3-значным совпадением, не отбрасывая повторение, поэтому мне пришлось использовать отрицательный результат, соответствующий границе слова. Это похоже на то, чтобы поставить ^ с самого начала.

(?! \ Б) (\ d {3} (? = (\ D {3}) * $))


По существу это предотвращает выражение из сопоставления с начало строки.
Что было бы плохо.

Смежные вопросы