10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

正規表現で後方参照の否定はできない(.)[^\1]

Last updated at Posted at 2016-04-25

自分が日本語で調べた限り見つからなかった。

9=9あ=あというx=xを満たす正規表現は
(.)=\1
と後方参照で表せられる。
(任意の一文字=先に使った任意の一文字と同じ文字)
では、9=9を弾いて、9=8x=2のみをマッチさせたい場合、
左辺に出た文字以外を右辺で使いたい。
正規表現の否定は[^否定したい文字]なので、
左辺の後方参照を否定する。
(.)=[^\1]
しかしこれは正しく動かなかった。
理由は不明であるが、文字クラス[]内ではメタ文字が一部を除き機能しないことに由来するのかもしれない。


ではどうするか
求めるものは
先に使用した任意の文字列以外の任意の文字列
正規表現には単純なAND演算子がなく、そもそも後方参照の否定が難しい

腑に落ちないが、否定先読みを使うと似たようなことができそうだ。

なお、私は正規表現の先読みや後読みは何度解説を読んでも理解できていない。
鵜呑みにはしないでいただきたい。

否定先読みを使うと、こう書ける。
(.)=(?!\1).

否定先読みを使うことで、
=の後が先に使った任意の一文字でなければ、=の後は任意の一文字である
というふうになる。と思う。
先に=(?!\1)x=xの可能性を排除しているので、のちの.x以外の場合にしか評価されない。

否定する後方参照が複数になった場合は、グループ化を使用する。

☓ 98=9
☓ 98=8
◯ 98=7

9でもなく8でもないはこう

(.)(.)=(?!(?:\1|\2)).

ORを(|)で表現するならば、後方参照対象からはずさなければ未定義になったりするので、後ろのグループ化に悪影響を及ぼす。
なので、(?:)で対象から外す。

今回は一文字単位だったが、もっと複雑なものはどうだろうか。
正規表現は否定が苦手、というわけでは無いが、難易度が少し上昇する予感だ。

なお、可読性は著しく下がる。
((.)(?!\2)(.))\1(?!(?:\2|\3))(.)\4\3

確認サイト

10
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?