
テキストファイルを操作したいです。次の形式のブロックがたくさん含まれています。
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
)。ただし、foo
2 番目のコピーでは行が省略されます。
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は私が学びたい言語のリストの次の言語です...;)