複数の行を含むファイルがあり、両方の行が特定のパターンに適合する場合は行を結合したいと考えています。
パターンに適合する行を見つけて、次の行を取得できることはわかっています。
grep -E -A1 'Pattern' filename
しかし、次の行もパターンに適合するかどうかをどのように確認し、2 つを結合するにはどうすればよいでしょうか?
たとえば、次のようなファイルがあります。
Hello
i
am
John
Smith
パターンの例は次のようになります。
'^[A-Z][a-z]+'
したがって、この場合、両方の行が大文字で始まる場合は、行を結合したいと思います。
達成したい出力は次のようになります。
Hello
i
am
John Smith
答え1
/^[A-Z][a-z]+/{
:a
N
/\n[A-Z][a-z]+/{
s/\n/ /
b a
}
}
として保存しjoin.sed
、実行します: sed -Ef join.sed file
。
行がパターンに一致する場合、次の行をパターン スペースに追加し、その行もパターンに一致する限り、改行文字をスペースに置き換えるループを開始します。
GNU Sed の場合は、これを 1 行にまとめることができます。
sed -E '/^[A-Z][a-z]+/{:a;N;/\n[A-Z][a-z]+/{s/\n/ /;b a}}' file
あるいは、Awk スクリプト の場合join.awk
、パターンは次のように指定する必要がありますp
。
{
if($0~p)c+=1
else c=0
printf "%s%s", (c>1 ? " " : ors), $0
ors=ORS
}
END{print ""}
実行するには: awk -f join.awk p='^[A-Z][a-z]+' file
。
答え2
sed
区切り文字としてヌル文字を使用する( -z
):
$ sed -z 's/\([A-Z][a-z]\+\)\n\([A-Z][a-z]\+\)/\1 \2/'
Hello
i
am
John Smith
答え3
Raku (旧称 Perl_6) の使用
raku -e 'given lines.join("\n") { S/ $<first>=[<upper><lower>+] \n $<last>=[<upper><lower>+] /$<first> $<last>/.put};'
サンプル入力:
Hello
i
am
John
Smith
goodbye
サンプル出力:
Hello
i
am
John Smith
goodbye
上記は、Perl系言語の1つであるRakuでコーディングされたソリューションです。データはgiven
Rakuでは の形式で提供されますlines
が、Rakuのlines
ルーチンは入力を自動的に処理するため、データはjoin
改行で区切られます。これは少し複雑に思えるかもしれませんが、Rakuのルーチンはデータを遅延して読み取るという利点がありますlines
。つまり、上記のコードはすべきであるメモリ効率が高い。
RakuはS///
「非破壊的」演算子を実装しており、これはよく知られているs///
演算子(Rakuにもそれがあります)と似ています(同一ではないかもしれませんが)。大文字の演算子S
には、「元の文字列をそのまま残し、$/ (一致変数) の代わりに結果の文字列を返します。」
演算子の対応する(左)半分内ではS///
、名前付きキャプチャが採用されています。正規表現エンジンは最初に を検索して[<upper><lower>+]
名前付きキャプチャに割り当て$<first>
、次に (改行)を検索し\n
、最後に別の を検索して[<upper><lower>+]
、今度は名前付きキャプチャに割り当てます$<last>
。最後に、演算子の置換(右半分)内でS///
、2つの名前付きキャプチャを$<first> $<last>
使用して左側の一致を置き換えますが、とスペースとそれなし間に改行\n
を入れます。
同じことを実現する別の方法を以下に示します。コードでは、名前付きキャプチャを省略し、代わりに を使用して、キャプチャ マーカー<(\n)>
内にあるものを除くすべてのものを一致オブジェクトから削除します<(…)>
。次に、置換で、がスペース\n
に置き換えられます。
raku -e 'put S/ [<upper><lower>+] <(\n)> [<upper><lower>+] / / given lines.join("\n");'
[注: 上記のコードは、 のような部分をGeorge\nHerbert\nWalker\nBush
4 行から 3 行に折りたたむだけです ( George Herbert\nWalker\nBush
)。 の行ごとに連続する出現をすべて[<upper><lower>+]
1 行で返したい場合は、遠慮なくその質問を投稿してください。]
https://docs.raku.org/language/regexes#S///_非破壊的置換
https://docs.raku.org/language/regexes#index-entry-regex__Named_captures-Named_captures
https://raku.org