7

sed特定のパターンに囲まれたパターンが行内に存在する場合、そのパターンを抽出したい場合に使用できますか?

次の行を含むファイルがあるとします。

近所の人に言われることを[/恐れて/]恐れて、自殺を敢えてしない人がたくさんいます。

/*アドバイスは、すでに答えを知っている*/が知りたくない場合に求めるものです。

どちらの場合も、最初に発生するパターン、つまりそれぞれのケースで' [ /' または ' 'の行をスキャンし、次のパターンを保存して、それまでパターンを終了する必要があります。つまり、それぞれ ' ]' または ' ' です。/*/*/

要するに, 必要ですfear.answer可能であれば, 複数の行に拡張できますか? ある意味で, 出口パターンが同じ行とは異なる行で発生した場合.

提案やアルゴリズムの形でのあらゆる種類のヘルプを歓迎します。返信ありがとうございます

4

3 に答える 3

4
use strict;
use warnings;

while (<DATA>) {
    while (m#/(\*?)(.*?)\1/#g) {
        print "$2\n";
    }
}


__DATA__
There are many who dare not kill themselves for [/fear/] of what the neighbors will say.
Advice is what we ask for when we already know the /* answer */ but wish we didn’t.

ワンライナーとして:

perl -nlwe 'while (m#/(\*?)(.*?)\1/#g) { print $2 }' input.txt

内側の while ループは、/g修飾子とのすべての一致間で繰り返されます。後方参照により、同一の\1開始/終了タグのみが一致することが保証されます。

複数の行にまたがるブロックを一致させる必要がある場合は、入力を丸呑みする必要があります。

use strict;
use warnings;

$/ = undef;
while (<DATA>) {
    while (m#/(\*?)(.*?)\1/#sg) {
        print "$2\n";
    }
}

__DATA__
    There are many who dare not kill themselves for [/fear/] of what the neighbors will say. /* foofer */ 
    Advice is what we ask for when we already know the /* answer */ but wish we didn’t.
foo bar /
baz 
baaz / fooz

一発ギャグ:

perl -0777 -nlwe 'while (m#/(\*?)(.*?)\1/#sg) { print $2 }' input.txt

-0777スイッチとは、ファイルの丸呑みを引き起こします。$/ = undefつまり、すべてのファイルがスカラーに読み込まれます。/sまた、ワイルドカード.が改行に一致するように修飾子を追加しました。

正規表現の説明:m#/(\*?)(.*?)\1/#sg

m#              # a simple m//, but with # as delimiter instead of slash
    /(\*?)      # slash followed by optional *
        (.*?)   # shortest possible string of wildcard characters
    \1/         # backref to optional *, followed by slash
#sg             # s modifier to make . match \n, and g modifier 

ここでの "魔法" は、後方参照で星が必要になるのは、その*前に星が見つかった場合だけであるということです。

于 2012-06-19T14:37:53.900 に答える
1

すばやく汚い方法でawk

awk 'NF{ for (i=1;i<=NF;i++) if($i ~ /^\[\//) { print gensub (/^..(.*)..$/,"\\1","g",$i); } else if ($i ~ /^\/\*/) print $(i+1);next}1' input_file

テスト:

$ cat file
There are many who dare not kill themselves for [/fear/] of what the neighbors will say.

Advice is what we ask for when we already know the /* answer */ but wish we didn't.
$ awk 'NF{ for (i=1;i<=NF;i++) if($i ~ /^\[\//) { print gensub (/^..(.*)..$/,"\\1","g",$i); } else if ($i ~ /^\/\*/) print $(i+1);next}1' file
fear

answer
于 2012-06-19T14:57:44.010 に答える
1

シングルラインマッチ

本当に sed でこれを行いたい場合は、区切られたパターンが同じ行にある限り、比較的簡単に抽出できます。

# Using GNU sed. Escape a whole lot more if your sed doesn't handle
# the -r flag.
sed -rn 's![^*/]*(/\*?.*/).*!\1!p' /tmp/foo

複数行の一致

sed で複数行のマッチを実行したい場合、状況は少し悪くなります。しかし、それは確かに行うことができます。

# Multi-line matching of delimiters with GNU sed.
sed -rn ':loop
         /\/[^\/]/ { 
             N
             s![^*/]+(/\*?.*\*?/).*!\1!p
             T loop
         }' /tmp/foo

トリックは、開始区切り文字を探し、終了区切り文字が見つかるまでループ内で行を追加し続けることです。

終了区切り文字が本当にある限り、これは非常にうまく機能します。それ以外の場合、ファイルの内容は、sed がパターン空間を見つけるまで、またはファイルの最後に到達するまで、パターン空間に追加され続けます。これにより、特定のバージョンの sed や、パターン空間のサイズが手に負えなくなる非常に大きなファイルで問題が発生する可能性があります。

詳細については、GNU sed の制限と非制限を参照してください。

于 2012-06-20T08:53:02.113 に答える