您能否从字符串创建Python列表,同时将特定关键字中的字符保持在一起?
我想从字符串中的字符创建一个列表,但要将特定的关键字放在一起 例如: 关键词:汽车、公共汽车 输入:您能否从字符串创建Python列表,同时将特定关键字中的字符保持在一起?,python,python-2.7,Python,Python 2.7,我想从字符串中的字符创建一个列表,但要将特定的关键字放在一起 例如: 关键词:汽车、公共汽车 输入: "xyzcarbusabccar" 输出: ["x", "y", "z", "car", "bus", "a", "b", "c", "car"] 使用re.findall。先在关键词之间切换 >>> import re >>> s = "xyzcarbusabccar" >>> re.findall('car|bus|[a-z]', s
"xyzcarbusabccar"
输出:
["x", "y", "z", "car", "bus", "a", "b", "c", "car"]
使用
re.findall
。先在关键词之间切换
>>> import re
>>> s = "xyzcarbusabccar"
>>> re.findall('car|bus|[a-z]', s)
['x', 'y', 'z', 'car', 'bus', 'a', 'b', 'c', 'car']
如果您有重叠的关键字,请注意,此解决方案将找到您遇到的第一个关键字:
>>> s = 'abcaratab'
>>> re.findall('car|rat|[a-z]', s)
['a', 'b', 'car', 'a', 't', 'a', 'b']
您可以将[a-z]
部分替换为您喜欢的任何部分,例如\w
,或者简单的
来匹配任何字符,从而使解决方案更加通用
简要解释为什么这样做以及为什么正则表达式[a-z]| car | bus不起作用:
正则表达式引擎从左到右尝试交替选项,并“渴望”返回匹配项。这意味着一旦其中一个选项完全匹配,它就会考虑整个替换匹配。此时,它不会尝试任何其他选项,而是停止处理并立即报告匹配。使用“[a-z]| car | bus”
,引擎将在看到字符类[a-z]中的任何字符时报告匹配,并且永远不会继续检查“car”或“bus”是否也可以匹配
s = "xyzcarbusabccar"
import re
print re.findall("bus|car|\w", s)
['x', 'y', 'z', 'car', 'bus', 'a', 'b', 'c', 'car']
或者,对于任何非空白字符,可以使用\S
:
s = "xyzcarbusabccar!"
import re
print re.findall("bus|car|\S", s)
['x', 'y', 'z', 'car', 'bus', 'a', 'b', 'c', 'car', '!']
只要确保你的顺序正确,如果你想要最长的匹配,先放更长的单词
In [7]: s = "xyzcarsbusabccar!"
In [8]: re.findall("bus|car|cars|\S", s)
Out[8]: ['x', 'y', 'z', 'car', 's', 'bus', 'a', 'b', 'c', 'car', '!']
In [9]: re.findall("bus|cars|car|\S", s)
Out[9]: ['x', 'y', 'z', 'cars', 'bus', 'a', 'b', 'c', 'car', '!']
上述解决方案确实很好,但如果关键字字典很长,它很容易变得混乱(可能无法实现) 我建议将关键字存储在树中(利用冗余),这样更节省空间 如果关键词是
[“艺术”、“at”、“atm”、“公共汽车”、“can”、“汽车”]
字典如下所示
.
^
/ ¦ \
/ ¦ \
a b c
^ ^ ^
/ \ \ \
r t u a
^ ^ ^ ^
/ / \ \ / \
t m /0 s n r
^ ^ ^ ^ ^
/ / \ \ \
/0 /0 /0 /0 /0
keywords = ["car","at","atm","bus"]
keywordsTree = Tree('')
for keyword in keywords:
keywordsTreeNode = keywordsTree
for character in keyword:
if not keywordsTreeNode.has_child(character):
keywordsTreeNode.add_child(Tree(character))
keywordsTreeNode = keywordsTreeNode.get_child(character)
keywordsTreeNode.add_child(Tree('/0'))
______________
¦ ¦
- a -> c -> a -> r -> t ->
¦______________¦
我将其设置为二进制,因为它更易于绘制。节点“/0”
具有单词结尾(虚拟字符)的意义,而“
是根
我实现了这个简单的树类来构建树和必要的函数
class Tree(object):
def __init__(self, name='root', children=None):
self.name = name
self.children = {}
if children is not None:
for child in children:
self.add_child(child.name,child)
def __repr__(self):
return self.name
def add_child(self, node):
assert isinstance(node, Tree)
self.children[node.name] = node
def has_child(self,name):
return name in self.children
def get_child(self,name):
return self.children[name]
def print_tree(self,level=0):
sys.stdout.write('-' * level)
print self.name
for childTag in self.children:
self.children[childTag].print_tree(level+1)
给定关键字,我们可以使用如下代码构造结构
.
^
/ ¦ \
/ ¦ \
a b c
^ ^ ^
/ \ \ \
r t u a
^ ^ ^ ^
/ / \ \ / \
t m /0 s n r
^ ^ ^ ^ ^
/ / \ \ \
/0 /0 /0 /0 /0
keywords = ["car","at","atm","bus"]
keywordsTree = Tree('')
for keyword in keywords:
keywordsTreeNode = keywordsTree
for character in keyword:
if not keywordsTreeNode.has_child(character):
keywordsTreeNode.add_child(Tree(character))
keywordsTreeNode = keywordsTreeNode.get_child(character)
keywordsTreeNode.add_child(Tree('/0'))
______________
¦ ¦
- a -> c -> a -> r -> t ->
¦______________¦
最后,我们搜索输入中的关键字。下面的解决方案为输入中的给定位置提供从该位置开始匹配的所有关键字
inputWords = "xyzcarbusabccar8hj/0atm"
output = []
lengthInput = len(inputWords)
for position in range(0,lengthInput):
##add by default the character
# allMathcedKeyWords = [inputWords[position]]
allMathcedKeyWords = []
keywordsTreeNode = keywordsTree
searchPosition = position
curMathcedWord = ''
while searchPosition < lengthInput and keywordsTreeNode.has_child(inputWords[searchPosition]) :
keywordsTreeNode = keywordsTreeNode.get_child(inputWords[searchPosition])
curMathcedWord = curMathcedWord + inputWords[searchPosition]
if (keywordsTreeNode.has_child("/0")):
allMathcedKeyWords.append(curMathcedWord)
searchPosition += 1
if len(allMathcedKeyWords)==0:
allMathcedKeyWords = inputWords[position]
output.append(allMathcedKeyWords)
print output
对于上面的代码来说,重要的是单词末尾的虚拟字符是两个字母(“/0”
),并且永远不会匹配(即使组合出现在上面详述的输入序列中)。此外,它处理任何字符串字符(对于输入和关键字-也不需要像re.findall()
中那样引入转义字符)
从该输出列表中,您可以决定要执行的操作。如果您需要re.findall
的解决方案,请查找某个位置的最长匹配单词(或基于关键字逻辑顺序),然后跳转该单词包含的字符数
更进一步地说,输入中的每个字符都是一个顶点,当您找到一个单词时,请在匹配单词的最后一个字符后从该位置向对应的下一个顶点添加一条边。最短路径算法将再次为您提供上述解决方案。这样构造输出将再次提高空间效率并打开通往更复杂算法的大门
例如,使用关键字“car”
和“art”
以及art和输入序列“acart”
生成的图形如下所示
.
^
/ ¦ \
/ ¦ \
a b c
^ ^ ^
/ \ \ \
r t u a
^ ^ ^ ^
/ / \ \ / \
t m /0 s n r
^ ^ ^ ^ ^
/ / \ \ \
/0 /0 /0 /0 /0
keywords = ["car","at","atm","bus"]
keywordsTree = Tree('')
for keyword in keywords:
keywordsTreeNode = keywordsTree
for character in keyword:
if not keywordsTreeNode.has_child(character):
keywordsTreeNode.add_child(Tree(character))
keywordsTreeNode = keywordsTreeNode.get_child(character)
keywordsTreeNode.add_child(Tree('/0'))
______________
¦ ¦
- a -> c -> a -> r -> t ->
¦______________¦
复杂性分析
Space : longest_word_length * number_of_letters_in_keywords
input_length + input_length * input_length (worst case-fully connected graph)
Time : input_length * longest_word_length
input_length + input_length * input_length (worst case-fully connected graph)
很好的解决方案。使用
'[a-z]|'+'|'.join(关键字)
将使以编程方式构建正则表达式变得更容易。@SuperBiasedMan谢谢。这将是'|'.join(关键字)+'[a-z]“
,但是,顺序是至关重要的,因为正则表达式引擎从左到右尝试替代方法,并渴望返回匹配结果。这就是为什么解决方案有效,也许我应该编辑一个解释。啊,我真傻!我不太使用正则表达式,我只是认为其他顺序更可读。