我有一个垂直文件,其中每个单词(标记)位于 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>
问题是有时字符编码错误A或者A在第一列中,例如
<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>
我需要找到这些字符并删除整个文档结构。所以,如果我发现A在一行上,我需要删除<doc...>
所有行之间的全部内容</doc>
。
我的文件有十亿行,其中大约几千行包含错误的编码字符。
我使用 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>
,我们检查标志是否仍然设置;如果是这样,我们显示缓冲区。最后,无论是否设置了标志,每一行都会添加到我们的缓冲区中。