查找特定字符串并删除整个结构

查找特定字符串并删除整个结构

我有一个垂直文件,其中每个单词(标记)位于 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 解析器。但是,在这种情况下,以下方法可能可以作为解决方法:

  1. 从文件中删除所有空白行:

    sed -i '/^\s*$/d' file
    
  2. 在每个之前添加一个空行<doc>

    sed -i 's/<doc/\n\n<doc/' file 
    
  3. 用户 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>,我们检查标志是否仍然设置;如果是这样,我们显示缓冲区。最后,无论是否设置了标志,每一行都会添加到我们的缓冲区中。

相关内容