主に感想。

を書いています。

正規表現についてのメモ

正規表現について勉強したことのメモ。 正規表現の確認にはrubularというサイトを使う。

文字自体を表す正規表現

  • .は「任意の1文字」を表す
  • \wは「英単語を構成する文字(半角英数字とアンダースコア)」を表す
  • \dは「半角数字1文字」を表す
  • \tは「タブ文字」を表す
  • \nは「改行文字」を表す
  • \sは「空白文字(スペース、タブ文字、改行文字)」を表す

文字の条件を指定する正規表現

  • a|bは「aまたはb」を表す
  • abc|defは「文字列abcまたは文字列def」を表す
  • [abc]は「aまたはbまたはcが1文字」を表す
  • [0-9]は「0から9が1文字」を表す
  • [a-z]は「aからzが1文字」(文字コードで範囲を判定している)
  • [^a]は「aを除く任意の1文字」を表す
    • [^abc]は「aとbとcを除く任意の1文字」を表す

 文字の数量を指定する正規表現

これ単独ではなく、文字または文字を表す正規表現と組み合わせて使う。

  • {n}は「直前の文字がn文字」を表す
  • {n,m}は「直前の文字がn文字以上かつm文字以下」を表す
  • {n,}は「直前の文字がn個以上」を表す
  • {,n}は「直前の文字がn個以下」を表す
  • ?は「直前の文字が0個または1個」を表す
  • +は「直前の文字が1個以上」を表す
  • *は「直前の文字が0個以上」を表す
  • *+は条件にマッチする最長の文字列を返す。最短マッチが欲しい場合は、*?+?とする

最後のはいわゆる貪欲なマッチ(greedy match)を防ぎ、怠惰なマッチ(lazy match)を行うための方法。例えば、我輩は猫である。名前はまだ無い。という文章から一文目を抽出したい場合、^.+。だと最長マッチの我輩は猫である。名前はまだ無い。が抽出されてしまうので、代わりに^.+?。を使う。

位置を表す正規表現

文字そのものではなく、文字の前後の位置を表す。

  • ^は「行頭」を表す
  • $は「行末」を表す
  • \bは単語の境界を表す
  • (?=a)は「aの直前の位置」を表す(肯定の先読み、Positive Lookahead)
    • (?=abc)は「abcという文字列の直前の位置」を表す
    • (?=a|b|c)は「aまたはbまたはcの直前の位置」を表す
  • (?!a)は「aでない文字の直前の位置」を表す(否定の先読み、Negative Lookahead)
  • (?<=a)「aの直後の位置」を表す(肯定の後読み、Positive Lookbehind)
  • (?<!a)「aでない文字の直後の位置」を表す(否定の後読み、Negaive Lookbehind)

先読み/後読みはちょっと複雑で覚えづらいが、利用場面は多い。例えば、aaa,bbb,ccc,dddのようなcsv文字列から3列目の値だけを置換したい場合、カンマそのものはキャプチャしたくないので、(?<=,)(.*?)(?=,)でカンマの間の文字をキャプチャし、\2で参照すれば良い。

キャプチャ関連の正規表現

  • ()で挟んだ部分はグループ化、またはキャプチャされる
  • (?:)でキャプチャを防ぐ
  • キャプチャした文字列は正規表現内でも\1\2といった連番で参照できる(後方参照)

後方参照は例えば、HTMLソースの中から<p></p>もしくは<span></span>タグで囲われている文字列を抽出したい場合、<(p|span)>.*<\/p|\/span>とすると、<p></span><span></p>のように間違ったタグで囲われたものまで抽出されてしまう。このような場合は<(p|span)>.*<\/\1>とすることで、正しく抽出することができる。(<\/\1>の初めのバックスラッシュは、閉じタグのスラッシュをエスケープするためのもの)