藤岡さん
全体として、僕が不具合に遭遇してから考えて調べたことを遡ることになりま
す。ごゆっくり、どうぞ。
> なぜそんなことができるのかを説明して欲しいのです。
> ステップを追って、動作を言葉で説明して欲しい。
僕なんかの言葉より、パイソンのデバッガが出している過程を1つ1つ追った
ほうが正確だと思います。けれど、頑張ってみます。
例はまず単純なほうを使いますね。
=== test.txt ========
aaa
---
=====================
といった入力を
=== kek.txt =========
aaa
---
=====================
としたい。
「デリミタ(---)の前の行が空行でないなら空行を入れる」これが課題
です。
------- test1.sed -------
# all seds, OK except gsed3 (GNU3 + mb1.07)
$!N #(0)
/^aaa\n---$/{ #(1)
s/\n/\ #(2) s/\n/\n\n/ の意味。(5)のため空行追加。
\ #
/ #
P #(3) 「aaa」出力
s/^aaa\n// #(4) これにより PS は「\n---」となる
}
P #(5) 「\n」出力
D #(6)
------------------------
基本的に、外枠のN; P; Dのサイクルで複行のパターンスペースを作ります。
言うまでもなく、 sedデフォルトの自動読み込みは最初の1行のみで、そのあと
はこのスクリプトのN; P; Dのサイクルが順次次行を読み込んでいくという展開
になります。
(1)以降で、その複行が
aaa\n---
である場合の処理をします。もちろん前の行を調べているのはこの部分です。
(aaaがマッチしなければ、{ }の外に出てP; D。)
マッチした場合も、aaaはいずれ出力されねばなりませんが、 そのような文字
(aaaのこと) が存在するなら、 改行をaaaの後ろに付加しなければなりません
(デリミタの前に改行文字を入れる、と言っても同じこと)。step (2).
(4)は、自前の D です。(3)の P のあと D ができなための工夫と考えて下さい。
(4)で D してしまうと制御がstep (0)に戻ってしまうのです。制御をスクリプト先
頭に戻すことなく、つまり } 以降のP; Dへといくように、パターンスペースの
最初のセグメントを消去しています。
------------------------------------------------------------------
さて、
C:\>gsed3 --version
GNU sed version 3.02 + multi-byte extension 1.07
以外では、ここまででは問題が出ません。 そしてgsed3に僕はこだわりがない
ので(Perl-like regexが使えませんので)、よいのです。また、上の「aaa\n---」
は、 あくまでonigsedのバグ出し(恐い言葉、ごめんなさい)のために考案した
テストです。
ではどういう場合にonigsedで問題が出るのか。デリミタの前が「aaa」でなく、
もう少し汎用的に記述した場合、つまり「空行でないなら」と記述した場合です。
これは
aaa
でなく
[^\n][\n^]*
とsedのBREでは記述されると思います。([^\n]*と略記して同じだと思いますが)
すると、スクリプトはこうなります。
------- test2.sed -------
$!N
/^[^\n][^\n]*\n---$/{
s/\n/\
\
/
P
s/^[^\n][^\n]*\n// #(*)
}
P
D
-------------------------
で、onigsedだけ動かない。デバッガにより(*)の箇所でおかしくなっているこ
とが判明した。#2437で書いたとおり
# s/aaa\n// # こうなら誤って2つ消しはしない
# s/[^\n]*\n// # これだと2つ消す
s/[^\n]\+\n// # これでも2つ消す
と少し詰められた、というわけです。これで十分ではないとも思いますが。
(アンサパンドその他の件は、どうも話が変な方向へ行きそうなので割愛しました。)
最後に、デバッガの出力を載せておきます。
>python sedsed -d -f c:\test2.sed c:\test.txt >c:\kek.txt
--- egsed (GNU sed version 4.0.7) #は出力
PATT:aaa$
COMM:$ !N
PATT:aaa\n---$
COMM:/^[^\n][^\n]*\n---$/ {
COMM:s/\n/\\N\\N/
PATT:aaa\n\n---$
COMM:P
aaa #
PATT:aaa\n\n---$
COMM:s/^[^\n][^\n]*\n//
PATT:\n---$
COMM:}
COMM:P
#
PATT:\n---$
COMM:D
PATT:---$
COMM:$ !N
PATT:---$
COMM:/^[^\n][^\n]*\n---$/ {
COMM:P
--- #
PATT:---$
COMM:D
--- onigsed #は出力
PATT:aaa$
COMM:$ !N
PATT:aaa\n---$
COMM:/^[^\n][^\n]*\n---$/ {
COMM:s/\n/\\N\\N/
PATT:aaa\n\n---$
COMM:P
aaa #
PATT:aaa\n\n---$
COMM:s/^[^\n][^\n]*\n// ;ここがおかしい
PATT:---$ ;「\n」が2つともなくなっている
COMM:}
COMM:P
--- #
PATT:---$
COMM:D
Bunta