Python 查找包含来自另一个列表的子字符串的列表元素的有效方法 list1=[“新年快乐”、“游戏结束”、“快乐故事”、“等一下”] 列表2=[“快乐”、“新”、“保持”]

Python 查找包含来自另一个列表的子字符串的列表元素的有效方法 list1=[“新年快乐”、“游戏结束”、“快乐故事”、“等一下”] 列表2=[“快乐”、“新”、“保持”],python,list,substring,Python,List,Substring,假设我有两个字符串列表,我想使用一个新列表来存储这两个列表的匹配对,如下所示: list3=[[“新年快乐”、“快乐”]、[“新年快乐”、“新”]、[“一个快乐的故事”、“快乐”]、[“坚持”、“坚持”]] 这意味着我需要得到一个列表中的所有字符串对,而它们的子字符串在另一个列表中 实际上那是关于一些中国古代文字资料。第一个列表包含10至13世纪的人名,第二个列表包含该时期所有诗歌的标题。古代中国人经常在作品的标题中记录他们的社会关系。例如,有人可能会写一首题为“献给我的朋友王安石”的诗。在这

假设我有两个字符串列表,我想使用一个新列表来存储这两个列表的匹配对,如下所示:

list3=[[“新年快乐”、“快乐”]、[“新年快乐”、“新”]、[“一个快乐的故事”、“快乐”]、[“坚持”、“坚持”]]
这意味着我需要得到一个列表中的所有字符串对,而它们的子字符串在另一个列表中

实际上那是关于一些中国古代文字资料。第一个列表包含10至13世纪的人名,第二个列表包含该时期所有诗歌的标题。古代中国人经常在作品的标题中记录他们的社会关系。例如,有人可能会写一首题为“献给我的朋友王安石”的诗。在这种情况下,第一个名单中的“王安石”应该与这个头衔相匹配。还有像《为我的朋友王安石和苏轼》这样的案例,标题中有不止一个人。基本上,这是一个巨大的工作,涉及30000人和160000首诗

以下是我的代码:

list3=[]
对于清单1中的i:
对于清单2中的j:
如果str(i).计数(str(j))>0:
清单3.追加([i,j])
我使用str(I),因为python总是将我的中文字符串作为浮点。这段代码确实有效,但速度太慢了。我必须想出另一个办法。谢谢

使用进行搜索,通过。正则表达式引擎可以在文本搜索中计算出匹配元素,这比嵌套的
for
循环要好得多

我将在这里使用更好的变量名,以便更清楚地显示列表的内容<代码>标题是您正在搜索的诗歌标题,
名称
是您试图匹配的内容<代码>匹配的是要生成的
(标题、名称)
对:

import re

titles = ["happy new year", "game over", "a happy story", "hold on"]
names = ["happy", "new", "hold"]

by_reverse_length = sorted(names, key=len, reverse=True)
pattern = "|".join(map(re.escape, by_reverse_length))
any_name = re.compile("({})".format(pattern))
matches = []

for title in titles:
    for match in any_name.finditer(title):
        matches.append((title, match.group()))
上述操作将生成所需的输出:

>>> matches
[('happy new year', 'happy'), ('happy new year', 'new'), ('a happy story', 'happy'), ('hold on', 'hold')]
名称按长度反向排序,以便在使用相同前缀的较短名称之前找到较长的名称;e、 g.
Hollander
Holland
之前找到

模式
字符串是从您的姓名创建的,以形成一个
…|…|…
替代模式,这些模式中的任何一个都可以匹配,但是正则表达式引擎将在序列中找到前面列出的模式,而不是后面列出的模式,因此需要按长度反向排序。整个名称模式周围的
(…)
括号告诉正则表达式引擎在一个组中捕获该部分文本。循环中的
match.group()
调用可以提取匹配的文本

该调用用于防止名称中的“元字符”以及具有特殊含义的字符(如
^
$
)等)被解释为其特殊的正则表达式含义

然后(编译模式上的and方法)按从左到右的顺序查找不重叠的匹配项,因此它永远不会匹配较短的子字符串,并为我们提供了提取每个子字符串的匹配项的机会。如果您想了解元数据和其他元数据(如果您需要的话),这将为您提供更多选项。否则,也可以在这里使用

如果要在带有西文字母的文本中使用上述内容,而不是在中文中使用上述内容,则可能还需要添加单词边界标记,
\b

any_name = re.compile("\b({})\b".format(pattern))

否则,可以匹配较大单词的部分子字符串。由于中文没有单词边界字符(如空格和标点符号),因此您不希望在此类文本中使用
\b

如果列表较长,可能需要为给定单词出现的句子建立某种“索引”。创建索引大约需要在
list1
中的所有句子中找到
list2
中的第一个单词(它必须在所有句子中的所有单词上循环),一旦创建了索引,就可以更快地在O(1)中找到包含单词的句子

结果:

[['happy new year', 'happy'],
 ['a happy story', 'happy'],
 ['happy new year', 'new'],
 ['hold on', 'hold']]

这将使用
str.split
在空格处拆分单词,但如果句子更复杂,例如,如果它们包含标点符号,则可以使用带单词边界的正则表达式
\b
,并可能对句子进行规范化(例如,转换为小写或应用词干分析器,但不确定这是否适用于中文)。

因为python总是将我的中文字符串作为浮点:这实际上是不可能的,我非常怀疑
str(floatingpoint\u值)
会产生有用的名称匹配。更有可能的是,您的输入结构中某处存在混合数据,并且某些数据实际上是浮点值。您是否愿意使用
pandas
解决方案?@Erfan是的,我使用它从excel中获取数据file@MartijnPieters我用
str()尝试了代码
,它返回正确的结果。在此之前,我遇到了类似“float”对象没有属性“count”的错误。名称列表来自sqlite3数据库,我将其转换为列表。标题列表来自excel文件,我使用
pandas
读取它,然后将其转换为列表。这两个列表都不包含我相信是ins浮点值。不过,中文文本不能那么容易地拆分成单词。这就是为什么我在正则表达式解决方案中省略了
\b
边界锚。非常感谢!我尝试了这种方法,在大约32秒内得到了正确的答案。唯一的问题是我仍然需要使用
str()
指向我的标题列表。这是因为熊猫的缘故吗??我试图打印我以前标题列表中所有元素的类型,它们都显示了
。但是我仍然需要
str()
操作来避免错误。@YunfeiYang:无法访问确切的da
[['happy new year', 'happy'],
 ['a happy story', 'happy'],
 ['happy new year', 'new'],
 ['hold on', 'hold']]