4

VI を使用して最初のオカレンス/インスタンスを置き換えるのは非常に簡単です。

    :%s/search/replace/args

しかし、ここに.csv形式/ファイルの私のデータセットがあります:

"192.168.2.1","www.google.com","2009/01/11_10:00"," What a great website"
"192.168.2.2/driving/is/fun","-","2009/03/22_00:00","Driving website"
"192.168.2.4/boating/is/crazy","-","2009/03/22_00:00","Boating Website"
"192.168.2.5","www.cars.com","2009/04/27_00:00","What a good car website"

最初の行には 4 つの列があることがわかります。これは .csv 形式の理想的な行です。

ただし、2 行目には 4 つの列がありますが、最初の列は IP アドレスのみを受け入れ、それ以上のものは受け入れないため、192.168.2.2/driving/is/fun を削除するか、「,」.csv 区切り文字で区切る必要があります。

viでは、以下を使用できました。

    :/^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//s/\//","/

これは次のことを行います:

  • /^"\d{,3}.\d{,3}.\d{,3}.\d{,3}/ - スラッシュ / を使用して最初の IP で検索を開始するアンカーを設定します。例、2 行目: "192.168.2.2/

  • /s///","/ - IP アドレスの末尾の / を .csv 区切り文字 "," に置き換えます

これは VI/VIM でうまく機能し、一度に 1 行ずつ必要なものを正確に置き換えます。ただし、データ セットははるかに大きく、次の vi 検索と置換を手動で使用すると時間がかかります。VI / VIMは一度に1行しか実行しないため、スクリプトを作成するか、別の解決策を見つけようとしています.

明らかに、私は次のことを試しました:

次のように、置換の開始部分にファイル全体の % を追加します。

    :/^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//%s/\//","/

変更する必要があるすべてのエントリが強調表示されますが、エラーが発生します。

    E492: Not an editor command: /^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//%s/\//

これはかなり紛らわしいです。

最終的には、sed/perl を使用して、ファイル全体の編集を一度にスクリプト化したいと考えています。

それで..

"192.168.2.2/ --> "192.168.2.2","

すべての行で最初に出現。

どんな助けでも大歓迎です..

ありがとう!

4

3 に答える 3

4

vi/vim では、置き換えたい検索範囲を指定できます。この場合:%s、すべての行を置き換えます。

:%s/search/replace/g

以下を指定することもできます。

:2,5s/search/replace/g      Replace on lines 2-5
:.,$s/search/replace/g      Replace from current line (.) to last line ($)
:.,+3s/search/replace/g     Replace on the current line (.) and the two next lines (+3)
:g/^asd/s/search/replace/g  Replace on lines starting with 'asd'. 

次に、これをより単純なパターンと組み合わせて、ファイル全体で必要な置換を行うことができます。

:%s/^\("[^/"]*\)[^"]*"/\1"/

これにより、CSV の最初のエントリから IP アドレスの後のすべてが削除されます。

:%s/^\("[^/"]*\)\/\([^"]*\)"/\1","\2/

これにより、最初のエントリが IP アドレスと残りのエントリに分割されますが、これは IP の後にスラッシュがある行に対してのみ行われます。あなたがしようとしていたのは、パターンを見つけ、その行に移動してから置き換えることでした。その場合に「%」を追加すると、コマンドが無効になりました。

于 2012-06-13T20:03:21.403 に答える
3

ViMでは、次のことを試してください。

 :%s/^\("\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\)\(\/[^"]\)/\1","\2

つまり、検索/置換の代わりに、グローバル(つまり、最初の行から最後の行への%ショートカット)置換を使用します。検索パターンを置換パターンに移動し、IPアドレスとパスを別々のグループにキャプチャしました。次に、それらを元に戻し、その間に押し込みます。1,$","

于 2012-06-13T20:22:58.363 に答える
2

より単純なパターンでやりたいことを実行できます。

s/^\("[^/"]*\)[^"]*"/\1"/

これは次のとおりです: 行頭に一致し、一致グループを開始します: a"に一致し、スラッシュでも a"でもない任意の数の文字に一致し、一致グループを閉じ、a 以外の任意の数の文字に一致し、a"に一致し"ます。一致グループの内容に a を加えたものに置き換え"ます。

上記のパターンは、スクリプトを作成するのに非常に簡単です。Python の例を次に示します。

#!/usr/bin/env python
import re
import sys

if len(sys.argv) != 3:
    print("Usage: log_file_cleaner <input_file> <output_file>")
    sys.exit(1)

pat = re.compile(r'^("[^/"]*)[^"]*"')

with open(sys.argv[1]) as in_f, open(sys.argv[2], "w") as out_f:
    for line in in_f:
        line = re.sub(pat, r'\1"', line)
        out_f.write(line)

with注: 2 つのopen()呼び出しを実行するには、最新バージョンの Python が必要です。Cygwin に行き詰まっている場合は、上記を 2 つのネストされたwithステートメントに編集して、それぞれが単一のopen()呼び出しを行うようにすることができます。

于 2012-06-13T20:03:47.450 に答える