如何从文档中删除重复的短语?

时间:2012-01-09 10:08:46

标签: bash text nlp duplicates duplicate-removal

是否有一种从大文本文件中删除重复内容的简单方法?能够检测到重复的句子(用“。”分隔,甚至更好地找到句子片段的副本(例如4个字的文本片段)将会很棒。

6 个答案:

答案 0 :(得分:2)

正如其他人所指出的那样,删除重复的单词很容易。比这更复杂的事情,你进入Natural Language Processing领域。 Bash不是最好的工具 - 你需要一个文明时代稍微优雅的武器。

我个人推荐Python,而NLTK(自然语言工具包)。在深入研究之前,可能值得一读NLP,以便您了解实际需要做什么。例如,文献中的“4字文本”被称为4克(在通用情况下为n-grams)。该工具包将帮助您找到这些,等等。

当然,可能有Python / NLTK的替代品,但我不熟悉。

答案 1 :(得分:1)

删除重复的短语并保留原始顺序:

nl -w 8 "$infile" | sort -k2 -u | sort -n | cut -f2

管道的第一个阶段在每行前面加上行号以记录原始订单。第二阶段使用唯一的开关集对原始数据进行排序。 第三个恢复原始顺序(排序1.列)。最终剪切删除了第一列。

答案 2 :(得分:0)

如果您首先uniq文本文件,则可以删除与sort重复的(必须完全相等)。

$ cat foo.txt
foo
bar
quux
foo
baz
bar
$ sort foo.txt
bar
bar
baz
foo
foo
quux
$ sort foo.txt | uniq
bar
baz
foo
quux

除此之外,没有简单的方式来做你想做的事。 (你怎么会分开句子?)

答案 3 :(得分:0)

您可以将grep与反向引用结合使用。 如果你写grep "\([[:alpha:]]*\)[[:space:]]*\1" -o <filename>,它将匹配任何两个相同的单词。即如果文件内容为this is the the test file,则会输出the the

(解释[[:alpha:]]匹配任何字符az和AZ,星号*后面意味着它可能会显示任意次数,\(\)用于分组以反向引用它稍后,[[:space:]]*匹配任意数量的空格和制表符,最后\1匹配找到的确切序列,并附在\(\)括号中

同样,如果你想匹配一组4个单词,连续两次重复,表达式将类似grep "\(\([[:alpha:]]*[[:space]]*\)\{4\}[[:space:]]*\1" -o <filename> - 它将匹配例如a b c d a b c d.*

现在我们需要在匹配之间添加任意字符序列。从理论上讲,这应该在反向引用之前插入grep "\(\([[:alpha:]]*[[:space]]*\)\{4\}.*\1" -o <filename>,即{{1}},但这对我来说似乎不起作用 - 它只匹配任何字符串并忽略所说的反向引用

答案 4 :(得分:0)

简短的回答是没有简单的方法。通常,任何解决方案都需要首先决定如何将输入文档拆分成块(句子,每组4个单词等),然后比较它们以查找重复项。如果输出中非重复元素的排序与输入中的顺序非常重要,那么这只会使问题更加复杂。

最简单的bash友好解决方案是根据您选择的任何条件将输入拆分为行(例如,在每个.上拆分,尽管安全地执行此引用有点棘手)然后使用标准副本检测机制(例如| uniq -c | sort -n | sed -E -ne '/^[[:space:]]+1/!{s/^[[:space:]]+[0-9]+ //;p;}'然后,对于每个结果行,远程输入文本。

假设你有一个文件被正确地分成每个“句子”的行,那么

uniq -c lines_of_input_file | sort -n | sed -E -ne '/^[[:space:]]+1/!{s/^[[:space:]]+[0-9]+ //;p;}' | while IFS= read -r match ; do sed -i '' -e 's/'"$match"'//g' input_file ; done

可能就够了。当然,如果$match包含sed解释为模式的任何数据,它将会崩溃。如果这对您来说是个问题,则应采用另一种机制来执行实际替换。

注意:如果您使用的是GNU sed,则上面的-E开关应更改为-r

答案 5 :(得分:0)

我刚刚在python中创建了一个脚本,它完全符合我最初的想法:

import string
import sys

def find_all(a_str, sub):
    start = 0
    while True:
        start = a_str.find(sub, start)
        if start == -1: return
        yield start
        start += len(sub)

if len(sys.argv) != 2:
    sys.exit("Usage: find_duplicate_fragments.py some_textfile.txt")
file=sys.argv[1]
infile=open(file,"r")
text=infile.read()
text=text.replace('\n','') # remove newlines
table = string.maketrans("","")
text=text.translate(table, string.punctuation) # remove punctuation characters
text=text.translate(table, string.digits) # remove numbers
text=text.upper() # to uppercase
while text.find("  ")>-1:
    text=text.replace("  "," ") # strip double-spaces

spaces=list(find_all(text," ")) # find all spaces

# scan through the whole text in packets of four words
# and check for multiple appearances.
for i in range(0,len(spaces)-4): 
    searchfor=text[spaces[i]+1:spaces[i+4]]
    duplist=list(find_all(text[spaces[i+4]:len(text)],searchfor))
    if len(duplist)>0:
        print len(duplist),': ',searchfor
顺便说一句:我是一个蟒蛇新手,所以欢迎任何关于更好的蟒蛇练习的提示!