5

//#...改行文字までの文字列があります。これが正規表現であることがわかりました..#([^\n]*)

私の質問は、次の条件が一致する場合、ファイルからこの行をどのように削除するかです

4

9 に答える 9

28

あなたの正規表現はいくつかの点でひどく選ばれています:

  1. 2つのスラッシュを具体的に一致させる代わりに、..2つの文字を一致させるために使用します。これは、スラッシュを区切り文字としても使用しているときに、スラッシュを一致させる方法がわからないためと考えられます。(実際には、#3で説明するように、ドットはほとんどすべてに一致します。)

    スラッシュで区切られた正規表現リテラル内では、スラッシュ//をバックスラッシュで保護するだけでスラッシュを一致させることができます。/\/\//。ただし、より良い変形は、より長い形式の正規表現リテラルを使用するm//ことです。ここで、区切り文字を選択できます。m!!。区切りにはスラッシュ以外のものを使用するので、エスケープせずにそれらを書くことができますm!//!perldocperlopを参照してください。

  2. 文字列の先頭に固定されていないため、どこでも一致します。^前に文字列の開始アサーションを使用します。

  3. ワイルドカード[^\n]だけのもっと簡単な書き方がある場合は、「改行以外のすべての文字」と一致するように書きました。.それはまさにそれを行います–改行以外のすべての文字に一致します。

  4. 一致の一部をグループ化するために括弧を使用していますが、グループは定量化されておらず(1回以外の回数だけ一致できることを指定していません)、それを維持することに関心がありません。したがって、括弧は不要です。

全体として、それはそれを作りますm!^//#.*!.*ただし、キャプチャされていない(または数量詞のあるもの)を正規表現の最後に置くことは*、文字列が一致するかどうかが変わることはないため、意味がありません*

だからそれはあなたにを残しますm!^//#!

ファイルから行を削除することに関しては、他のみんなが説明したように、それを1行ずつ読み、残しておきたいすべての行を別のファイルに印刷します。より大きなプログラム内でこれを行わない場合は、perlのコマンドラインスイッチを使用して簡単に行うことができます。

perl -ni.bak -e'print unless m!^//#!' somefile.txt

ここで、-nスイッチはperlに、指定されたコードの周りにループを配置させ、コマンドラインで渡したすべてのファイルを順番に読み取ります。-iスイッチ(「インプレース」の場合)は、スクリプトから出力を収集し、各ファイルの元の内容をそれで上書きするように指示します。このオプションの.bakパラメーターは、-iperlに、元のファイル名にちなんで名前が付けられたファイルに元のファイルのバックアップを保持するように指示します.bak。これらすべてのビットについては、perldocperlrunを参照してください。

より大きなプログラムのコンテキスト内でこれを実行する場合、安全に実行する最も簡単な方法は、ファイルを2回開くことです。1回は読み取り用で、もう1回は書き込み用にIO::AtomicFileを使用します。IO :: AtomicFileは、正常に閉じられた場合にのみ元のファイルを置き換えます。

于 2008-09-17T07:56:04.033 に答える
5

特定の正規表現に一致するファイル内のすべての行を除外するには:

perl -n -i.orig -e 'print unless /^#/' file1 file2 file3

-iスイッチの後の「.orig」は、指定された拡張子(.orig)を持つファイルのバックアップを作成します。バックアップが必要ない場合はスキップできます(-iを使用するだけです)。

-nスイッチを指定すると、perlはファイルの各行に対して命令(-e'...')を実行します。行は$_に格納されます(これは、多くの命令のデフォルトの引数でもあります。この場合は、印刷と正規表現の一致です)。

最後に、-eスイッチの引数は、「行の先頭の#文字と一致しない限り、行を出力します。

PS。行が常に印刷されることを除いて、-nのように動作する-pスイッチもあります(検索と置換に適しています)

于 2008-09-17T07:40:15.210 に答える
2

他の人が指摘しているように、最終目標が で始まる行を削除することだけである場合、//#パフォーマンス上の理由から、おそらくgreporを使用する方がよいでしょうsed:

grep -v '^\/\/#' filename.txt > filename.stripped.txt

sed '/^\/\/#/d' filename.txt > filename.stripped.txt

また

sed -i '/^\/\/#/d' filename.txt

インプレース編集を好む場合。

perl では、正規表現は次のようになることに注意してください。

m{^//#}

これは、文字列の先頭にある 2 つのスラッシュとそれに続く # に一致します。

m{pattern}より馴染みのある/pattern/. この構文は過度のエスケープを回避する簡単な方法であるため、早い段階でこの構文について学習してください。一致させたいものに応じて、またはとm{^//#}同じくらい効果的に書くことができます。明快さを追求してください - 正規表現は、読みやすさを損なう回避可能なバックスラッシュのとげのある森がなければ、解読するのが十分に困難です。真剣に、欠けた歯と詰め物をしたワニ、またはアルプスの小さなASCII絵のように見えます.m%^//#%m#^//\##m/^\/\/#/

スクリプトで発生する可能性のある問題の 1 つは、ファイル全体が文字列、改行、およびすべてに丸呑みされている場合です。そのケースを防御するには、正規表現で /m (複数行) 修飾子を使用します。

m{^//#}m

これにより、文字列の先頭と改行の後に ^ を一致させることができますm{^//#.*$}正規表現修飾子/g, /m,を使用して一致する行を削除または一致させる方法があると思うでしょうが/s、ファイルを文字列に丸呑みしたが、そのコピーを作成したくない場合 (質問をお願いします)そもそもなぜそれが文字列に丸呑みされたのか.) それは可能であるべきですが、遅れており、答えが見えていません. ただし、それを行う「簡単な」方法の1つは次のとおりです。

my $cooked = join qq{\n}, (grep { ! m{^//} } (split m{\n}, $raw));

元の文字列のインプレース編集ではなく、コピーを作成します$raw

于 2008-09-17T09:15:07.200 に答える
1

これには本当にperlは必要ありません。

sed '/^\/\/#/d' inputfile > outputfile

私は3秒未満です。

于 2008-09-17T07:26:46.773 に答える
0

あなたの正規表現が正しいとは思いません。

最初に ^ で始める必要があります。そうしないと、行のどこでもこのパターンに一致します。

次に、 は である..必要があり\/\/ます。さもなければ、任意の 2 文字と一致します。

^\/\/#[^\n]*おそらくあなたが望むものです。

次に、EricSchaefer の言うことを実行し、ファイルを 1 行ずつ読み取り、一致しない行だけを書き込みます。

--
bmb

于 2008-09-17T06:18:54.203 に答える
0

ファイルを 1 行ずつ読み取り、正規表現に一致しない行のみを新しいファイルに書き込みます。行を削除することはできません。

于 2008-09-17T06:06:44.140 に答える
0

それは行の先頭から始まりますか、それともどこにでも表示できますか? 以前の s/old/new が必要な場合。後者の場合、私はそれを理解する必要があります。後方参照は何らかの形で使用できるのではないかと思います。

于 2008-09-17T06:07:04.997 に答える
0

次のことを試してください。

perl -ne 'print unless m{^//#}' input.txt > output.txt

Windows を使用している場合は、一重引用符ではなく二重引用符が必要です。

grepでも同じことができます

grep -v -e '^//#' input.txt > output.txt
于 2008-09-17T07:09:22.307 に答える
0

ファイル内の各行を反復処理し、パターンに一致する場合はその行をスキップします。

my $fh = 新しい FileHandle 'ファイル名'
    or die "ファイルを開けませんでした - $!";

while (my $line = $fh->getline) {
    next if $line =~ m{^//#};
    $line を印刷します。
}
$fh を閉じます。

これにより、「//#」で始まる行を除く、ファイルのすべての行が出力されます。

于 2008-09-17T07:11:07.997 に答える