各単語(タグ)が4列の別々の行にある垂直ファイルがあります。次のように文書化されたメタ構造もあります<doc>
。<s>
<doc name="sth" url="http">
<p>
<s>
Here here k1gInSc1 here
is be k1gMnPc2 be
a a k2eAgMnPc1d1 a
sentence sentence k1gMnPc1 sentence
<g/>
. . kIx.
</s>
</p>
</doc>
問題は時々文字エンコーディングが間違っていることです。ㅏまたはㅏたとえば、最初の列では
<doc name="sth" url="http">
<p>
<s>
Here here k1gInSc1 here
is be k1gMnPc2 be
Ă Ă k? Ă
sentence sentence k1gMnPc1 sentence
<g/>
. . kIx.
</s>
</p>
</doc>
これらの文字を見つけて文書全体の構造を削除する必要があります。だから私が見つけたらㅏ<doc...>
1行からすべての行間のすべての項目を削除する必要があります</doc>
。
私のファイルには10億行があり、そのうち約1000行に誤ってエンコードされた文字が含まれています。
私はgrepを使って間違った文字を見つけます。
xzcat file.vert.xz | grep -i "Ă\|Ĺ\|ľ\|ş\|Ä" > file_bad_characters.txt
どのようにこれらの文字を検出し、その行だけでなく、<doc>
構造間のテキスト全体を削除できますか?
答え1
正しいアプローチは、適切なXMLパーサーを使用することです。ただし、この場合、次の方法を使用すると回避策になる可能性があります。
ファイルから空白行をすべて削除します。
sed -i '/^\s*$/d' file
各項目の前に空白行を追加します
<doc>
。sed -i 's/<doc/\n\n<doc/' file
「行」が「段落」(空白行の前のテキスト部分)として定義されているユーザーPerlの「段落モード」:
perl -00 -ne 'print unless /[ĂĹľşÄ]/' file > newfile
または、ソースファイルを置き換えるには、次の手順を実行します。
perl -i.bak -00 -ne 'print unless /[ĂĹľşÄ]/' file
重要<doc...
:すべてがタグ内にあるよく構造化されたファイルを想定しています。
答え2
残念ながら、これはgrepだけでは実行できないことです。 grepが提供できない行の一部のコンテキストを維持する必要があります。ただし、これを実行できる他の多くの言語があります。例は次のとおりですawk
。
awk '/<doc>/ {text=""; output=1}
/Ă|Ĺ|ľ|ş|Ä/{output=0}
{text = text $0 "\n"}
/<\/doc>/ {if(output==1){printf "%s", text}}"
これはバッファを生成し、text
入力でトークンを表示すると呼び出され、印刷するテキストを表すフラグを設定します。<doc>
禁止されている文字に会うとフラグがクリアされます。 token に会うと</doc>
フラグがまだ設定されていることを確認し、そうであればバッファを表示します。最後に、フラグが設定されているかどうかに関係なく、各行がバッファに追加されます。