これを解決するには、先読みと後方参照を使用できます。ただし、現時点では少なくとも 2 文字が必要であることに注意してください。開始文字と別の文字 ( による+
)。おそらく、2 番目の文字クラスを 0 回以上繰り返すことができるようにする必要があります+
。*
^(?!.*(.)\1)[a-zA-Z][a-zA-Z\d._-]*$
先読みはどのように機能しますか? まず、否定的な先読みです。内部のパターンが一致する場合、先読みによってパターン全体が失敗し、その逆も同様です。したがって、 2 つの連続する文字がある場合に一致するパターンを内部に持つことができます。まず、文字列 ( ) 内の任意の位置を探し.*
、次に単一の (任意の) 文字 ( .
)を一致させ、括弧でキャプチャします。したがって、その 1 文字はキャプチャ グループに入り1
ます。そして、このキャプチャ グループの後にそれ自体が続く必要があります (それを で参照します\1
)。したがって、内側のパターンは文字列内のすべての位置で試行されます (バックトラッキングのため)) それ自体が後に続く文字があるかどうか。これらの 2 つの連続した文字が見つかった場合、パターンは失敗します。それらが見つからない場合、エンジンは先読みが開始された場所 (文字列の先頭) に戻り、実際のパターンの照合を続行します。
または、これを 2 つの個別のチェックに分割することもできます。有効な文字と開始文字の 1 つ:
^[a-zA-Z][a-zA-Z\d._-]*$
そして、連続した文字の 1 つ (一致結果を反転できる場所):
(.)\1
これにより、コードの可読性が大幅に向上し (先読みよりもわかりにくいため)、パターン内の実際の問題を検出して、適切で役立つエラー メッセージを返すこともできます。