检查字符串是否包含另一个字符串的一定数量的单词

时间:2014-04-11 17:17:20

标签: python string

假设我们有一个字符串1 A B C D E F和一个字符串2 B D E(这些字母仅用于演示,实际上它们是单词)。现在我想知道是否有任何n一致的"单词"来自字符串1中的字符串2.要将字符串转换为"字词",我使用string.split()

例如n等于2,我想检查B DD E是否 - 按此顺序 - 在字符串1中{{ 1}}在字符串中不按此顺序排列,但B D是。

有没有人看到这样做的pythonic方式?

我确实有D E等于2的解决方案,但意识到我需要任意n。它也不是特别漂亮:

n

4 个答案:

答案 0 :(得分:2)

使用正则表达式很容易:

>>> import re
>>> st1='A B C D E F'
>>> st2='B D E'
>>> n=2
>>> pat=r'(?=({}))'.format(r's+'.join(r'\w+' for i in range(n)))
>>> print [(s, s in st1) for s in re.findall(pat, st2)]
[('B D', False), ('D E', True)]

关键是使用零宽度向前看以找到字符串中的重叠匹配。所以:

>>> re.findall('(?=(\\w+\\s+\\w+))', 'B D E')
['B D', 'D E']

现在构建n重复\w+找到的单词:

>>> n=2
>>> r'(?=({}))'.format(r's\+'.join(r'\w+' for i in range(n)))
'(?=(\\w+\\s+\\w+))'

现在因为你有两个字符串,所以使用Python的in运算符从正则表达式匹配到目标字符串产生s结果的元组。


当然如果你想要一个非正则表达式来做这个,只需用n生成n个字的子串:

>>> li=st2.split()
>>> n=2
>>> [(s, s in st1) for s in (' '.join(li[i:i+n]) for i in range(len(li)-n+1))]
[('B D', False), ('D E', True)]

如果你想要索引(任何一种方法),你可以使用str.find

>>> [(s, st1.find(s)) for s in (' '.join(li[i:i+n]) for i in range(len(li)-n+1)) 
...     if s in st1]
[('D E', 6)]

对于逐字逐句的正则表达式,请确保使用单词边界锚:

>>> st='wordW wordX wordY wordZ'
>>> re.findall(r'(?=(\b\w+\s\b\w+))', st)
['wordW wordX', 'wordX wordY', 'wordY wordZ']

答案 1 :(得分:1)

你可以像这样建立ngrams:

a = 'this is an example, whatever'.split()
b = 'this is another example, whatever'.split()

def ngrams(string, n):
    return set(zip(*[string[i:] for i in range(n)]))

def common_ngrams(string1, string2, n):
    return ngrams(string1, n) & ngrams(string2, n)

结果:

print(common_ngrams(a, b, 2))
{('this', 'is'), ('example,', 'whatever')}

print(common_ngrams(a, b, 1))
{('this',), ('is',), ('example,',), ('whatever',)}

请注意,棘手的位在带有zip function

的ngrams函数中
zip(*[string[i:] for i in range(n)]

这与

基本相同
zip(string, string[1:], string[2:])

表示n = 3.

另请注意,我们正在使用多组元组,这是性能最佳的......

答案 2 :(得分:0)

假设您有两个字符串(对于每个只包含一个字母的字符串,这很容易解决)

a = 'this is a beautiful day'
b = 'this day is awful'

然后得到b的所有单词也属于你写的

x = [x for x in b.split() if x in a.split()]

现在x包含(在一行代码之后)

['this', 'day', 'is']

然后检查x的序列组合(从0向上len(x))是否属于b

for i in range(len(x)):
    for j in range(i, len(x)+1):
        word = ' '.join(x[i:j])
        if word in b:
            print(word)

Exampleb的相同顺序打印a的{​​{1}}个单词的(order preservig)组合(在{{1}中进行小调整嵌套for)的语句

答案 3 :(得分:0)

longest common substring algorithm将在这里工作,如果你传入一个拆分列表而不是一个普通的字符串 - 还有额外的奖励,如果你传入的话,它还会给出最长的字符串中最长的字符串。未分裂的字符串。

def longest_common_substring(s1, s2):
    m = [[0] * (1 + len(s2)) for i in xrange(1 + len(s1))]
    longest, x_longest = 0, 0
    for x in xrange(1, 1 + len(s1)):
        for y in xrange(1, 1 + len(s2)):
            if s1[x - 1] == s2[y - 1]:
                m[x][y] = m[x - 1][y - 1] + 1
                if m[x][y] > longest:
                    longest = m[x][y]
                    x_longest = x
            else:
                m[x][y] = 0
    return s1[x_longest - longest: x_longest]