一括表示

− 野ざらし言 −

[3939] こんな正規表現はどう書く?

としき 2011/08/17(Wed) 22:31
http://www1.hinocatv.ne.jp/toshiki/
ニフティの過去ログを対象とした検索を考えます。
使うツールは、古いgrepとします。
つまり、新しすぎない正規表現を仮定します。

発言番号の20000番台(20000〜29999)に言及している行を一発で抽出したいときには、どのような正規表現を書けばよいでしょうか。必ずしも他の発言に言及したものでなくてもよいので、とりあえず、20000台の数字があるものが抽出できれば了とします。多少、余分なものが引っかかってもよいですが、抜けがないようなものを希望します。

私が途中まで考えて挫折したのは以下のような感じ。
まず、基本は

2[0-9][0-9][0-9][0-9]

です。
が、それ以上の長さの数字列が多量に引っかかるので、それを抑止するために

[^0-9]2[0-9][0-9][0-9][0-9][^0-9]

となります。
でも、こうすると、行頭や行末に発言番号が書かれているものが引っかからなくなります。
あと、単純に行頭に20000番台の数字があるものを引っかけると、当然ながら、言及している行だけではなく、20000番台の発言そのものの発言ヘッダも抽出されてしまいますが、これは避けたい。
例えて言えば、

[^0-9|^]2[0-9][0-9][0-9][0-9][^/0-9|$]

こんな感じの正規表現が書きたいわけです。
複数回grepを行えばなんとでもなると思うのですが、そこが頭の体操というか、一発で行いたいわけです。


どなたか、そんなことはできん、でもかまいませんので、知恵をお貸しいただけると幸いです。

[3940] Re: こんな正規表現はどう書く?

めざら 2011/08/19(Fri) 21:58
[3939]へのコメント http://homepage3.nifty.com/mezala/
 いろいろ試してみたのですが,わたしには無理でした。
 例え行頭の5桁にマッチさせないようにできても,/の次に5桁の近似の数があるので,どうしても発言ヘッダはマッチしてしまいますね。

 ここは素直に,量指定子の使える新しいgrepにした方がいいような気がするのですが…。

[3941] Re^2: こんな正規表現はどう書く?

としき 2011/08/20(Sat) 10:42
[3940]へのコメント http://www1.hinocatv.ne.jp/toshiki/
>  ここは素直に,量指定子の使える新しいgrepにした方がいいような気がするのですが…。

これを使うと、どうなります?
orの演算子とかも使えるようになるので、かなり楽だとは思うのですが、私のほうがそっちの正規表現に不慣れなもので、よくわからないのですよ。

[3942] Re^3: こんな正規表現はどう書く?

めざら 2011/08/20(Sat) 11:42
[3941]へのコメント http://homepage3.nifty.com/mezala/
 わたしも量指定子を実際に使ったことがありません。不慣れどころか,新しい正規表現は一切知りませんのです。

 例えば,[0-9]{5} と書くと5桁の数字にマッチするというものですよね。
 2万台なら,2[0-9]{4} というわけでしょうか。

 ん?
 2の前に数字があったら,6桁になってしまうのか…。これは,振り出しに…。

 単純に5桁の数字を[0-9]{5}で抽出するしかないのかなぁ。
 自分ならそうやって抽出しておいて,[0-9][0-9][0-9][0-9][0-9]/[0-9][0-9][0-9][0-9][0-9].+$をヌルに置換してしまうかなぁ…。

 でも2段階は許容できないんですよね,としきさんとしては。

[3943] Re^4: こんな正規表現はどう書く?

としき 2011/08/20(Sat) 19:12
[3942]へのコメント http://www1.hinocatv.ne.jp/toshiki/
>  でも2段階は許容できないんですよね,としきさんとしては。

実務では、2段階どころか、3段階で行って、無事に答えを得ています。
で、やっている最中に、頭の体操として考え始めたのですが、うまいこといかなかったもので、なんかよい方法はないものかいな、ということで質問させていただきました。まぁ、できるとしても相当難しそうだ、ということがわかっただけでも収穫です。

どうもありがとうございました。

[3944] Re^5: こんな正規表現はどう書く?

文太 2011/08/26(Fri) 05:19
[3943]へのコメント
 ずるいPerlな正規表現を使った場合(というか、それしかないはず…)。
 [^0-9]の否定は、それ自体で1字喰ってしまうのが面倒なのだと思う…。
 [^], [$]って、メタキャラの意味になりませんよね。
 まったく自信がありません。
 まぐれで「それっぽい」結果になった可能性大です。


--- t.grp --- regex 定義ファイル(コマンドラインだとオアがおいたをするかも?)
(?<!\d)2\d{4}(?!\d|/)
-------------

--- test.txt --- 対象テスト・ファイル
20000
200000

 20000
 20000/
 200000
 320000
 32000
---------------

--- コマンドライン&結果 ---
C:\>yagrep -ft.grp -P test.txt |to
20000
 20000
----------------------------

--- 鬼車定義 ---
\d		decimal digit char
(?=subexp)	look-ahead
(?!subexp)	negative look-ahead
(?<=subexp)	look-behind
(?<!subexp)	negative look-behind
----------------

[3945] Re^6: こんな正規表現はどう書く?

としき 2011/08/26(Fri) 08:47
[3944]へのコメント http://www1.hinocatv.ne.jp/toshiki/
>  ずるいPerlな正規表現を使った場合(というか、それしかないはず…)。

あ、ちょっと惜しい。
発言ヘッダは引っかかってほしくないけど、本文中の発言ヘッダの引用は引っかかってほしいのです。なので、「20000/20001」というパターンが行頭にある場合は除外するけど、そうでないときは引っかかってほしい。あ、でも、この場合「20001」のほうで引っかかってくるのか。ということを考えると、むちゃくちゃ面倒なので、やはり現実的には、2段階、あるいは3段階で処理するしかなさそう。とりあえず、「29999/30001」というパターンが行頭にある場合は引っかからず、引用符つきの場合なら引っかかる、くらいにしておきますか。

ついでながら、実務で私が取った方法。

[^0-9]2[0-9][0-9][0-9][0-9][^0-9]
^2[0-9][0-9][0-9][0-9][^0-9/]
[^0-9]2[0-9][0-9][0-9][0-9]$

この3つの検索結果をマージすることで、とりあえず、望んだ結果は得ています。

[3946] Re^7: こんな正規表現はどう書く?

文太 2011/08/26(Fri) 19:59
[3945]へのコメント
 泥縄ですねぇ。としきさんの3段階に漏れや拾いすぎがないなら(そう
見えましたが)、あれがスマートっぽいです。


>「20000/20001」というパターンが行頭にある場合は除外する
>けど、そうでないときは引っかかってほしい。 あ、でも、この場合「20001」の
>ほうで引っかかってくるのか。ということを考えると、むちゃくちゃ面倒なので、

 た、確かに、これはむちゃくちゃ面倒ですねぇ。
 あとでsedで削りましょう(※)。

--- t.sed --- #onigsed -R(分かんなくなるから、perlモードで)
/1\d{4}\/2\d{4}/d
-------------
(勝手に「1万台の番号/2万台の番号」と決めた。でも考えてみたら、こんなこと
あまり気にしないほうがようですね。そんなのあんまりしないでしょう。ヘッダもろ
ともタイプか…。ぶ、文太だ。)

>「29999/30001」というパターンが行頭にある場合は引っかからず、引用符
>つきの場合なら引っかかる、くらいにしておきますか。

 継ぎ足し、しました。

--- t1.grp ---
(?<!\d)2\d{4}(?!\d|/)
--------------

--- t2.grp ---
[^0-9]2\d{4}(?!\d)
--------------

--- コマンドライン ---
C:\>yagrep -ft1.grp -P test.txt >kek.txt
C:\>yagrep -ft2.grp -P test.txt >>kek.txt
C:\>onigsed -ft.sed -R kek.txt >result.txt
----------------------

 たぶん、sedで1つのスクリプトにするのが…。
 下も、自信ないですが。

--- t.sed --- 
#>Onigsed -R -ft.sed test.txt |to

/(?<!\d)2\d{4}(?!\d|\/)|[^0-9]2\d{4}(?!\d)/{
/1\d{4}\/2\d{4}/d
b}
d
-------------

 簡単な解説。
/A|B/ {/C/d;b} 
d
のような形。
 AとBのオアの条件。条件クリアならさらにCの条件。Cクリアならdelして
branch(分岐先がないので。ここから脱出し、また、最後のdelもしない)。
 上のA,Bをそもそもクリアできないど、自動del(sedは何もしないと全部
プリントしてしまうから)。

 Aは文頭・文末を含めた2万台の5桁数字。20000/の「/」付きも駄目。
 Bは、引用符がある場合。「/」付きを許す。
 Cは、19999/20000のように、後ろの2万台がヒットした場合。del。
 b (branch)では、Cでdelされようがされまいが、スクリプト末へジャンプ。

--- test.txt ---
29999/30001	拾うな
>29999/30001	拾え
19999/20000	拾うな
>19999/20000	拾うな
29999		拾え
 29999		拾え
>29999/30001
29999
 29999
----------------最後の3行は、文末用(?)

--- 結果 ---
C:\>Onigsed -R -ft.sed test.txt |to
>29999/30001	拾え
29999		拾え
 29999		拾え
>29999/30001
29999
 29999
------------

 あ、たぶん、1行にヒットしたりするのが複数あると、やはりミスはあるで
しょう。拾えないという痛いのもあるでしょうね。(※とリンク)

/(?<!\d)2\d{4}(?!\d|\/)|[^0-9]2\d{4}(?!\d)/{
b}

 としておいたほうがよさそう。これで、複数ヒット対策は…???
 防災と同じで、漏れるより拾い過ぎが良いでしょうね。

 以上です。

[3947] Re^8: こんな正規表現はどう書く?

としき 2011/08/27(Sat) 00:22
[3946]へのコメント http://www1.hinocatv.ne.jp/toshiki/
いやぁ、ありがとうございます。
やっぱり、むちゃくちゃというか、私の理解の範囲を超えつつあります。
(苦笑)

発端は、なんか簡単な解があるのではないか、というところだったんですがね。
決してそんなことはない、という意味で、数学の各種未解決問題のような感じになってしまいました。
ま、あまり本気にならずに、でも、ふとひらめいたりしたら、また教えてください。

ありがとうございました。

[3949] Re^9: こんな正規表現はどう書く?

文太 2011/08/27(Sat) 12:16
[3947]へのコメント
としきさん

>やっぱり、むちゃくちゃというか、私の理解の範囲を超えつつあります。
>数学の各種未解決問題のような感じになってしまいました。

 現実的にはこの問題は難しいですが、僕の半端解が難しそうに見えるのは、
たぶん、sedのコーディング(コマンドとロジック)のせいでしょう。

>発端は、なんか簡単な解があるのではないか、というところだったんですがね。

 正規表現って、ツールのコマンドとの兼ね合いの部分もありますから。
 でも、文頭・文末、否定、桁数指定。この条件で「簡単な解」はないと思う。
 文頭、文末の例外を拾うとしきさんの3行は明晰。僕がちゃんと読めないくらい
論理的でしたが。

>ま、あまり本気にならずに、でも、ふとひらめいたりしたら

 本気になっちゃった、というか、予想外にサクサクいったのです。「絶対ムリ」
と最初思ったから。すると、現実には、どの程度で妥協するかになり、手を動かし
てやってみるしかない、となるのですよねぇ…。漏れは見えないけど…。

 ではでは。

↑ このページの先頭