2013-05-30 25 views
12

Szukałem krótkiego kodu, który umieści przecinki w zbiorze liczb, aż dotrę do this site.Regex czyta od prawej do lewej

Kod:

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; 
} 

działa naprawdę świetnie. Mając ten przykład zestaw numer:

addCommas('83475934.89'); 

powróci "83,475,934.89", ale kiedy odczytać kodu, oczekuję na powrót 8,3,4,7,5,934.89 ale to strony wyjaśnia, że ​​

\d+ w połączeniu z \d{3} dopasuje grupa 3 liczb poprzedzonych dowolną ilością liczb. To sprawia, że ​​wyszukiwanie polega na zastąpieniu od prawej do lewej.

I jestem taki zdezorientowany. Jak ten kod jest czytany od prawej do lewej? Co oznacza $1 i $2?

+1

'$ 1' i' $ 2' reprezentują grupy przechwytywania – smerny

+3

Nie czyta się od prawej do lewej strony, przechowuje się od prawej do lewej. Raczej. Zauważ, że możesz uczynić tę funkcję jeszcze krótszą - naprawdę niewielka zmiana w regex usuwa potrzebę zrobienia 'split()' na przecinku, zapisując trzy linie kodu: http://jsfiddle.net/TqCRh/ – nnnnnn

+0

@nnnnnn Dobry połów! –

Odpowiedz

5

pasuje ona od prawej do lewej, ponieważ wykorzystuje chciwy wzór pasujący. Oznacza to, że najpierw znajduje wszystkie cyfry (\ d +), , a następnie próbuje znaleźć \ d {3}. Na przykład pod numerem 2421567.56 najpierw dopasowałaby cyfry aż do "." - 2431567 - następnie działa wstecz, aby dopasować kolejne 3 cyfry (567) w następnej części wyrażenia regularnego. Robi to w pętli, dodając przecinek między zmiennymi 1 $ i 2 $.

$ reprezentuje grupy dopasowania utworzone w wyrażeniu z nawiasami np. (\ d +) = 1 $ i (\ d {3}) = 2 USD. W ten sposób można łatwo dodawać postacie między nimi.

W następnej iteracji, zachłanne dopasowanie zatrzymuje się w nowo utworzonym przecinku i trwa do momentu, gdy nie może się równać> 3 cyfrom.

+0

+1 Kocham twoje wyjaśnienie. Teraz jest dla mnie jasne. – fiberOptics

3

To wyjaśnienie było dalej na tej samej stronie

Kod Wyjaśnienie: kod zaczyna się dzielenie ciąg na dwie części (nStr i nStrEnd), jeśli jest tam po przecinku. Wyrażenie regularne jest używane na nStr, aby dodać przecinki. Następnie dodaje się nStrEnd. Jeśli łańcuch nie miał nStrEnd tymczasowo usunięty, wówczas wyrażenie regularne by sformatować 10,0004 jako 10.0,004

Regular Expression Objaśnienie: \ d + w połączeniu z \ d {3} będzie pasuje do grupy 3 liczb poprzedzonych dowolną liczbą liczb. Ten szuka sposobu na zamianę z prawej na lewą.

$1 i $2 są przechwytywane mecze grupowe z wyrażenia regularnego. Możesz przeczytać więcej na ten temat na Regex Tutorial.

+0

+1 za udostępnienie tego samego link jak ja :) dobrze to i, no wiecie, za dostarczenie dobrej odpowiedzi (używając własnego źródła OP)! –

2

Kod odczytuje od prawej do lewej, poszukiwanie największego wiersza cyfr (\d+), po którym następuje 3 cyfry (\d{3}). 1 $ i 2 USD to odpowiednio największy rząd cyfr i 3 cyfry. Więc umieszcza przecinek między nimi, powtarzając ten proces, który może go sparsować w ten sposób.

14

To nie jest faktycznie czytanie od prawej do lewej. To, co się naprawdę dzieje, polega na tym, że wielokrotnie nakłada wzór (poprzez pętlę while) i zastępuje, dopóki nie pasuje do wzorca.Innymi słowy:

iteracji 1:

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

iteracji 2:

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

Powtórzenie 3:

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

Edycja:

Co oznacza 1 USD i 2 USD?

Są to odnośniki zwrotne do pasujących grup odpowiednio (\d+) i (\d{3}).

Oto wielki odniesienia dla uczenia się, jak wyrażenia regularne rzeczywiście działa:
http://www.regular-expressions.info/quickstart.html

+0

Lepszy sposób wyjaśnienia tego. – crush

+0

W Iteracji 1, czy mogę spodziewać się wyniku "834,75934.89"? – fiberOptics

+0

@fiberOptic s Nr 834,75934.89 to '(\ d +) (\ d {5})'. – JJJ

1

pisałem wyrażenia regularnego, który robi to samo w jednym przebiegu:

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

spróbować tego na przykład z różnymi numerami na początku:

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')); 
 
}


Spróbuję to rozbić:

Zignoruj ​​ten fragment na razie - Wrócę do tego.

(?! \ B) (\ d {3} (? = (\ D {3}) * \ b))


To wciąż czyta się od lewej do prawej próbuje przechwycić bloki składające się z 3 cyfr. Oto grupa przechwytująca.

(? \ B) (\ d {3} (= (\ d {3}) * \ b) )


jednak wewnątrz przechwytywania grupa, używa przecznicy.

(? \ B) (\ d {3} (= (\ d {3}) * \ b ))


uprzedzona poszukuje jakiegokolwiek wielokrotność 3 cyfr zakotwiczonych na końcu numeru - granica kończąca. Spowoduje to wyrównanie przechwytywania do wielokrotności 3 z prawego końca numeru. Oznacza to, że działa również z liczbami dziesiętnymi (chyba że są to więcej niż 3 miejsca po przecinku, w którym to przypadku będzie również umieszczać w nich przecinki).

(? \ B) (\ d {3} (= (\ d {3}) * \ b))


Problemem było to, że JavaScript nie obsługuje błędów atomowych, więc gdy liczba ma wielokrotność 3 cyfr, pasowała do pierwszych 3 cyfr i umieszczała przecinek na samym początku numeru.
Nie można dopasować postaci przed 3-cyfrowym dopasowaniem bez odrzucenia powtórzenia, więc musiałem użyć ujemnego wyprzedzenia, które pasuje do granicy wyrazów. Jest to przeciwieństwo stawiania ^ na początku.

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


zasadzie zapobiega ekspresji z dopasowania z początek ciągu.
Co byłoby złe.

Powiązane problemy