2006年03月08日

[正規表現] 文字列の否定

行頭・行末一気に挿入」の記事でC言語のソースをコメント化する正規表現を考えましたが、さらに、検索対象に既にコメント化された行がある場合は飛ばせるようにしたい。

しかし、コメントの「ある」行を探すのは、
(/\*|\*/)
ってできるのですが、コメントの「ない」行を探すために上記を否定する方法が分からない。

1文字単位の否定は、
[^a]
って感じでやればいいのですが、複数の文字がまとまった文字列の単位を否定するにはどうすればいいんだ?
ってことで探して見つけたのが以下のページ。

テキスト編集を極める!! 正規表現について - 秀丸Q&A
http://homepage2.nifty.com/jr-kun/hidemaru_qa/4_regulr.html

>[2-2] 「文字列の否定」について
> 今度はC言語のコメントを削除する例を考えてみましょう。
> C言語のコメントは "/*" と "*/" で囲まれた部分です。
> この場合も前節の HTML タグの削除でやったように "/*" と "*/"
> の間に "*/" を「否定」する 表現を入れてやればよい事は明白です。
> …と言いたい所ですが、正規表現には否定のキャラクタクラス指定と
> いう「文字」の否定をする表現はありますが、 直接「文字列」を否定
> する表現はありません。
> …もうおわかりでしょうが、"[^*/]" は「"*" でも "/" でもない1文
> 字」という意味であり、「"*/" でない文字列」という意味にはなりません。

ってことで、
[^(/\*|\*/)]
って感じで簡単に指定する方法はないらしい。

まあ、テキストエディタで手動でやる作業なので、例外ケースは手作業で直すってことで問題ないかってことで、行頭・行末一気に挿入」の正規表現をちょっとだけ改良。否定する文字に「/」を追加しました。
^([^/\r\n]+)$
「/」が単独で含まれている場合も引っかからなくなってしまうので、割り算をしている行が飛ばされてしまうというトホホな感じですが。

追記:
上記「秀丸Q&A」のページの続きに、
>C言語のコメントを消す
>"/*" と "*/" の間にある文字列のパターンは、以下のように表わすこと
>ができそうです。
> 「"/" 以外の文字」と「直前が "*" 以外の "/"」を組み合わせた文字列
>ここで、"/" の直前に "*" がないことを指定して実質的に「文字列の否
>定」をしていることに注意して下さい。
>以上のことを考慮して、ちゃんとコメントにマッチする(と思われる)パタ
>ーンを書いたものが以下です。
>検索文字列: /\*([^/]|[^*]/)*\*/
>("*" は メタキャラクタなので、キャラクタクラス指定の中にある "*"
>以外は "\" でエスケープしてあります。)

と書いてあったのでこれを参考にしたところ、以下のような正規表現で目的が達成できました。
^(([^/*\r\n]|/[^*]|\*[^/])+)$


この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/froo/50581540
この記事へのトラックバック
前回の「文字列の否定」の記事の正規表現にバグがありました。 現象は、テキストが「*/」ならばコメントと認識してヒットせず正しいが、「**/」と2つ並ぶとヒットしてしまうというもの。しかし「***/」と3つになるとまたヒットしなくなるという変な動き。「*」の数が奇数....
[正規表現] 先読み【浮浪プログラマーの始末書】at 2006年03月08日 21:11
この記事へのコメント
サクラエディタの場合は先読みが使えるので

^(?!.*(/\*|\*/)).*$

と書くのがスマートですね。

先読みが使えない場合は以下のサイトも
参考にすると良いと思います。

図解でみる正規表現入門 「文字列の否定」
http://funcchan.blog16.fc2.com/blog-entry-39.html
(名前クリックで飛べます)
Posted by 文字列の否定 at 2009年05月13日 21:56
おお、ありがとうございます。
3年前の記事なのですっかりチンプンカンプンですが(笑
Posted by 浮浪プログラマ at 2009年05月13日 22:46