2016-05-08 3 views
0

正規表現についてもう少し詳しく調べてみたい。この正規表現正規表現でグルーピングする

preg_replace("/(?=(.{3})*(.{4})$)/", "-", "1231231234"); 

Add a space on a string but counting right to left

結果は次のとおりです。123-123-1234

今、私は、数量やグループを試していますが、私は彼らが正常に動作することはできません。

この(PHP)

preg_replace("/(?=(.{3})*(.{4})(.{4})$)/", "-", "1212312312345678"); 

この理由:

preg_replace("/(?=(.{3})*(.{4}){2}$)/", "-", "1212312312345678"); 

両方の出力

12-123-123-12345678 

として私に大きな8文字グループを与える私はおそらく上の結果を予想2番目のケース{2}ですが、最初のケースではありません。

Iが意図期待される結果は次の通りであった:

12-123-123-1234-5678 

1)(のロジックは何{4})({4})=({8})の代わりです。。。 2つの異なるイベント?

2)適切なグループ化は何ですか?

答えて

1

正規表現の仕組みを誤解しているようです。私はあなたのためにそれを打破してみましょう:

(?=   lookahead assertion: the following pattern must match, but 
      will not consume any of the text. 
    (.{3})* matches a series of 3 characters, any number of times. In 
      other words, this consumes characters in multiples of 3. 
    (.{4})$ makes sure there are exactly 4 characters left. 
) 

このパターンは、あなたがダッシュ-を挿入したいすべての場所に空試合を生成します。そのため、preg_replace("/(?=(.{3})*(.{4})$)/", "-", "1231231234");は正しい場所にのダッシュを挿入します。空の文字列を置き換えることは挿入と同じです。のは、一例として、テキスト31231234を使用して、そのステップ・バイ・ステップを見てみましょう:パターンは、テキスト内の位置0に一致させることができなかった

  remaining text  remaining pattern  what happens 
step 0: 31231234   (.{3})*(.{4})$   (.{3})* matches one time 
step 1: 31234    (.{3})*(.{4})$   (.{3})* matches again 
step 2: 34     (.{3})*(.{4})$   (.{3})* fails to match another time 
step 3: 34     (.{4})$    (.{4}) fails to match -> backtrack 
step 5: 31234    (.{4})$    (.{4}) fails to match -> pattern failed to 
                match, no dash will be inserted. 

した後、それは位置1で再度チェックされます(残りのテキストがあります1231234):

  remaining text  remaining pattern  what happens 
step 0: 1231234   (.{3})*(.{4})$   (.{3})* matches one time 
step 1: 1234    (.{3})*(.{4})$   (.{3})* matches again 
step 2: 4     (.{3})*(.{4})$   (.{3})* fails to match another time 
step 3: 4     (.{4})$    (.{4})$ matches -> dash will be inserted 
                here, giving "3-1231234" 

同じことは、最終結果3-123-1234を与え、3つの文字後に再び起こります。つまり、グループ(.{4})$は、テキストの最後の4文字にダッシュを挿入しないことを指定します。最後の4文字を消費することで、残っている文字数が4文字未満の場合、パターンが一致しなくなります。そのため、(.{4})(.{4})$(.{4}){2}$の両方が8文字のブロックを生成します。パターンは8文字未満であれば一致できません。

は、最後の8つの文字で、別のダッシュを挿入するために、あなたは4つの文字.{4}の2つのグループを使用して、それらのいずれかをオプションにする必要があります:

(?=((.{3})*.{4})?(.{4})$) 
+0

詳細な説明をありがとうございます。もう1つの質問。 $を使用すると、実際にその時点からのバックトラック検索ですか、または何らかの種類の左から右への繰り返しですか?たとえば、この簡単なテストでは、https://regex101.com/r/eE6zK7/1には、一致が20ステップ後に見つかったと表示されています。 – Rafael

+0

@Rafael: '$'は文字列の終わりのアンカーに過ぎず、正規表現の "方向"には影響しません。 regex101上で "debugger"をクリックすると、それがどのように一歩一歩見えるかがわかります。 –

2

この場合、lookaheadsを使用していることに注意してください。通常のマッチングとは異なり、マッチしたものを実際には消費しません。

そこで最初の例では、2ゼロ幅マッチ、第123後の最初のものがあるので、ルックアヘッドは、1231234ため先読みが1234に一致する第123後秒、一致します。あなたは実際に何が一致するかを見るためにオンライン正規表現のテスターの1人を使用したいかもしれません、私の選択はregex101.comでしょう。

したがって、先読みを最後の4桁に一致させる必要があります。これを達成する方法の1つは(?=((.{3})*(.{4}))?(.{4})$)で、最初の部分はオプションです。

regex101でご覧ください。 N> = 0

は端からすべて4xN文字に一致するように端部に

+0

おかげで、はい、私はregex101で遊んされています。oを)、はい、私がもっと理解しやすいのは、あるパターンが他のパターンにもマッチすることです。 Ty。 – Rafael

1

(?=(.{3})*(.{4}){2}$)マッチ2×4 = 8つの文字をすべて3XN文字列を、1 < = N = 2 <、またはすべての3XN N> = 1の最後の8文字の文字シーケンス。

preg_replace("/(?=(.{4}){1,2}$)|(?=(.{3})+.{8}$)/", "-", "1212312312345678"); 
+0

Iwteresting。現時点では、私は縦棒を使用するとは思わないが、それは良い例のおかげです。 – Rafael