読者です 読者をやめる 読者になる 読者になる

この日記は私的なものであり、所属会社の見解ではありません。 GitHub: takahashikzn

先読みと行末

Regex

こういう文字列を

aaa,bbb,0
aaa,bbb,,1
aaa,bbb,2

このように置換したいと思いました。

aaa,bbb,,0
aaa,bbb,,1
aaa,bbb,,2

で、こういう正規表現を書いたのです。

s/(?<!,)(?=,.)$/,/g

この正規表現を先頭から説明すると、

  • 前の文字がカンマでない
  • 続く文字がカンマ、そして更に任意の一文字
  • その後はすぐに行末

である「位置」にマッチし(戻り読み、先読みは文字列ではなく「位置」にマッチする)
そこにカンマを挿入するという意図で書きました。

しかしこれが動かないという。

うーむ何故だ?

と暫く考えていたのですが、気づきました。行末記号が悪さをしていたということに。


先程の正規表現をよーく見てみると、

(?<!,)(?=,.)$
  • 前の文字がカンマでない
  • 続く文字がカンマ、そして更に任意の一文字
  • その後はすぐに行末

ではなく、

  • 前の文字がカンマでない
  • 続く文字がカンマ、そして更に任意の一文字

である位置、かつ

  • すぐに行末

であるという文字列にマッチせよという意味になります。
つまり、文字列の途中なのに行末という、ありえないマッチを指定していたわけです。

正解

この場合、

(?<!,)(?=,.$)

と書けばOK。これで本来意図した意味になります。