特定の部分をコピーして変更してファイルの内容を操作するには?

特定の部分をコピーして変更してファイルの内容を操作するには?

テキストファイルを操作したいです。次の形式のブロックがたくさん含まれています。

CLASS
   ...some stuff ...
END

各ブロックをコピーし、その内容の1行を追加および削除したいと思います。スクリプトを書くことはできますか?

答え1

わかったできる何でも書いてください。

ただし、これによりvimマクロが使用されます。 (まだ慣れていない場合はvim学ぶ必要があり、そうでない場合は無視してください)

いくつかの基本的なガイドライン:

q - マクロ記録の開始

qx - マクロの記録を停止し、名前を「x」として指定します。

@x - "x"というマクロを実行します。

マクロは、履歴セッション中に入力したすべてのコマンドを直ちに再実行します。

したがって、マクロに次のようにブロックをコピーさせるには:

q          start macro
/CLASS     jump to next "CLASS"
V          start selecting full lines
/END       jump to next "END
Y          yank selected lines (yank = copy)
j          scroll down one line
p          put (paste)
qd         stop recording and name the macro d

vimの使い方とvimマクロの良いリソースと例がたくさんあります。

価値ある点は、sedがvimのコマンドラインバージョンであるため、私が言う内容をsedに適用できるかもしれませんが、私はそれに慣れていないので保証できません。

~~編集~~

より便利にするもう一つのことは、複数のvimファイルを開くことができることです。複数のオープンファイルをバッファと呼びます。複数のファイル名を追加してこの機能を有効にできますvim(IEはvim *.txtすべてのtxtファイルを開きます)。

複数のバッファでマクロを実行するには、まずすべてのファイルを同時に開きます。次に、各バッファで:bufdo normal @xマクロ実行を使用します。x

:w現在のバッファが保存されていない場合は、次のバッファに切り替えようとして中断されるのを防ぐために、このステップをマクロの最後のステップにする必要があります。

:bn手動で次のバッファに移動します。

また見てくださいhttps://stackoverflow.com/questions/1291962/replay-a-vim-macro-until-end-of-buffer各行に対してマクロを実行する方法を学びます。リアンリアンカン:)

答え2

この目的のための自然なツールはawkとPerlです(スクリプトを作成すると仮定するとワンタイムで、自然ツールはインタラクティブエディタです)。以下は、すべてのCLASS...ブロックをコピーするawkスクリプトですEND(バランス調整をサポートしない:各ブロックがCLASS次のブロックと一致するEND)。ただし、foo2 番目のコピーでは行が省略されます。

awk '
  /^CLASS$/ { store = 1; }  # start storing
  store && ! /^foo$/ { hold = hold ORS $0; }  # if storing, maybe save line
  /^END$/ {
      $0 = $0 hold;  # append hold copy to current line
      store = 0; hold = "";  # end of block
  }
  1 { print; }  # print original line, with hold prepended if at end of block
'

これはsedソリューションです。あまり真剣に受け入れないでください。CLASS/行が厳密に交互に表示されない場合は、機能すると期待しないでくださいEND

sed -e '/^CLASS$/,/^END$/!b' \
    -e '/^CLASS$/{' -e 'h' -e 'b' -e '}' \
    -e '/^foo$/!H' \
    -e '/^END$/G'

答え3

使用される正確なツールは、タスクの詳細によって異なります。タスクが一度だけ発生した場合、またはvimでマクロの使用を検討できますemacs。本当にスクリプトを作成したい場合は、以下を見てみましょうsed

Sedはストリームエディタです。ストリームエディタは、入力ストリーム(ファイルまたはパイプの入力)で基本的なテキスト変換を実行するために使用されます。

これを行う正確な方法は状況によって異なりますが、PATTERNで始まる行の後に行を追加するには、次のようにします。

sed -e 's/\(^PATTERN.*\)/\1\nTextToAdd/' file.old > file.new

PATTERN で始まる行の前に行を追加するには:

sed -e 's/\(^PATTERN.*\)/TextToAdd\n\1/' file.old > file.new

PATTERN で始まる行の削除

sed -e 's/\(^PATTERN.*\)//' file.old > file.new

秘訣は、目的の線だけをキャプチャできる正しいパターンを見つけることです。

以下を実行してそれらを組み合わせることができます。

sed -e 's/\(^PATTERN1.*\)/\1\nTextToAdd/' -e 's/\(^PATTERN2.*\)/TextToAdd\n\1/' file.old > file.new

答え4

私のPythonソリューション:

file = open('a.txt', 'r')
arr = []
tmp = []
remember = False

for line in file:
    if "CLASS" in line:
        remember = True     # start storing lines
        tmp.append(line)    # we're storing lines in list
        continue            # go to next line
    if "END" in line:
        tmp.append(line)    # store line
        remember = False    # stop storing lines
        arr.append(tmp)     # add line to list
        tmp = []            # clear temp list
        continue            # go to next line
    if remember:
        tmp.append(line)    # add to list line between CLASS and END
file.close()

file = open('a.txt', 'a')
for tmp in arr:
    if '   ...some stuff ...1\n' in tmp:    # we can skip 
        continue                            # whole block if we find this
    for i in tmp:
        if "333" in i:  # we can skip only one line 
            continue
        file.write(i)
file.close()

awkバージョンよりも理解して修正するのが最も簡単だと思います(awkがわからない場合)...しかし、awkは私が学びたい言語のリストの次の言語です...;)

関連情報