Python 作为输入的单词列表上的正则表达式
例如,我有单词列表形式的句子Python 作为输入的单词列表上的正则表达式,python,regex,list,Python,Regex,List,例如,我有单词列表形式的句子 sentence = ['if', 'it', 'will', 'rain', ',', 'I', 'will', 'stay', 'at', 'home'] 现在我想找到条件子句['if','it','will','rain']。原则上,我可以从句子中创建一个字符串,例如,s=''。join(句子),I和使用正则表达式: p = re.compile(r'(\bif\b[a-zA-z0-9\'\s]+)\s*(,*)\s*(then|,)') for m in
sentence = ['if', 'it', 'will', 'rain', ',', 'I', 'will', 'stay', 'at', 'home']
现在我想找到条件子句['if','it','will','rain']
。原则上,我可以从句子中创建一个字符串,例如,s=''。join(句子)
,I和使用正则表达式:
p = re.compile(r'(\bif\b[a-zA-z0-9\'\s]+)\s*(,*)\s*(then|,)')
for m in p.finditer(s):
print m.start(1), m.end(1), '['+s[ m.start(1) : m.end(1) ]+']'
不需要对正则表达式进行判断,它只是一个简单的草图:)。这给了我输出:016[如果下雨]
到目前为止还不错。但现在我有点失去了与原始列表的联系。正则表达式给我字符位置,而不是单词/标记位置。理想情况下,我会得到0和3,这样我就知道条件子句是句子[0:3]
。我确信我可以编写一个方法,将字符位置映射到相应的列表索引,但我确信有更好的方法来完成这一切
当然,我可以忽略正则表达式,在列表上循环并得出正确的开始和停止条件。但是,正则表达式目前看起来相当整洁,因为它们“隐藏”以明确所需的条件。它们还简化了条件从句由其他单词或短语表示的情况,例如:
sentence = ['as', 'long', 'as', 'it', 'will', 'rain', ',', 'I', 'will', 'stay', 'at', 'home']
用正则表达式很容易反映这一点,我想使用循环会让人有点恼火
编辑:鉴于没有一个非常简单的解决方案,我继续我的想法,在正则表达式的字符串语句和原始单词列表之间创建一个映射:
def join(self, word_list, separator=' '):
mapping = []
string = separator.join(word_list)
for idx, word in enumerate(word_list):
for character in word:
mapping.append(idx)
for character in separator:
mapping.append(idx)
return string, mapping
将此方法应用于我的输入字符串,mapping=join(句子)
将导致:
mapping = [0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9]
现在,如果正则表达式给我0
和16
作为匹配范围,我就可以在原始句子
列表中用mapping[0]=0
和mapping[16]=4
查找索引。到目前为止,这似乎效果相当不错。由于我使用字符串的正则表达式进行匹配,我可以很容易地支持条件子句的替代公式,例如:
CONDITIONAL_PHRASES = ['if', 'as long as', 'even if']
...
p = re.compile(r"((%s)\s+[a-zA-z0-9'\s]+)\s*(then|,)" % '|'.join(CONDITIONAL_PHRASES))
再说一遍,我并不是说正则表达式已经很完美了,但它同时支持多个句子,并为条件从句提供了不同的指示词。注意:-如果只有一个
出现,如果和,
或则句子中的
我对你的正则表达式做了一些修改,增加了一个捕获组
re.compile("((\\bif\\b)[a-zA-z0-9\\'\\s]+)\\s*(,*)\\s*(then|,)")
您可以使用re.findall
作为
arr = re.findall(p, s)
arr[0][1]
包含第一个捕获组(stringif
),而arr[0][3]
包含第三个捕获组(stringthen
或,
)。您可以使用索引查找这两个的索引,如下所示:
start = sentence.index(arr[0][1])
end = sentence.index(arr[0][3])
现在,您可以使用
stri = ' '.join(sentence[start: end])
注1:-如果出现多个如果和,
或则在句子中(不重叠),您将必须迭代所有元组
arr = re.findall(p, s)
pos = 0 #It stores the last occurrence of matched group
for i, x in enumerate(arr):
start = sentence.index(x[1], pos)
end = sentence.index(x[3], pos)
stri = ' '.join(sentence[start: end])
print(stri)
pos = sentence.index(x[3], pos) + 1
注意2:-请记住,索引
在未找到字符串时引发异常。在执行上述操作之前先处理它在正则表达式之间切换会产生问题,因为您还必须在字符串之间切换输入,并保持它们的同步
一个列表比较函数,其中有一种OR:
sentence = ['if', 'it', 'will', 'rain', ',', 'I', 'will', 'stay', 'at', 'home']
phrase = ['if', [',', 'then']]
def findPhrase(phrase, full):
currentpos = 0
isFirst = True
result = []
for part in phrase:
if isinstance(part, list):
partOffset = 999
for subpart in part:
if subpart in full[currentpos:]:
if full[currentpos:].index(subpart) < partOffset:
partOffset = full[currentpos:].index(subpart)
if partOffset == 999:
return []
currentpos += partOffset
if isFirst:
result.append (currentpos)
else:
result[-1] = currentpos
continue
if not part in full[currentpos:]:
return []
currentpos = currentpos + full[currentpos:].index(part)
if isFirst:
result.append (currentpos)
else:
result[-1] = currentpos
# check for a single word match; should still return a range
# .. just duplicate last item
if len(result) == 1:
result.append(result[0])
return result
res = findPhrase (phrase, sentence)
if res == []:
print 'not found'
else:
print res
print sentence[res[0]:res[1]+1]
可以使用诸如“可选”和“任意匹配”之类的项来扩展findPhrase
函数,但是您必须将简单的基于数组的语法扩展到类似于字典的东西
目前,代码从一个找到的单词跳到下一个,忽略中间的任何内容。如果要添加一个显式的“*”
“短语”项,意思是“跳过任意数量的单词”,则需要(1)测试它是否是匹配短语中的最后一项(如果是,您可以发出句子的最后一项),和/或(2)执行一个单独的类似于前瞻的函数,检查短语
中的下一项是否出现在句子
中。(这非常接近于模仿正则表达式解析器。)取决于您想走多远,但在我看来,您已经进入了解析器领域的一半。因此,切换到基于解析器的解决方案可能会为您提供更坚实的基础但是一个快速的谷歌让我想知道,做一个句子.index(',')
是否更好,如果失败了句子.index('then')
。否则我会使用循环,比如cond\u end\u idx=(I代表I,枚举(句子)中的项,如果匹配('(然后|,)',项))
在你的句子中是否会出现多个if
和,
或then
?我还不清楚你在寻找什么。很明显,您希望靠近阵列结构。但我并没有从你的正则表达式中得到你最终想要匹配的东西。你想要不可能:)哇!真是太。。。简单?:/它可能有用,但我会去掉简单这个词。你的函数有31行。@zondo:point:)当我添加越来越多的函数时,我被冲昏头脑了。不过,总体思路应该很清楚。我没有用列表理解或类似的方法来缩短函数–你有什么办法吗?你的if
检查部分的子部分:
可以简化为if-1!=完整[currentpos]。查找(子部分)
。利用以下事实,x OP1 y OP2 z
与x OP1 y和y OP2 z
相同,但没有对y
进行两次求值。这可能是一个坏主意,因为它不容易阅读,但它应该更有效一点,而且它会减少一行。也许你应该试试:)拉德,谢谢你的努力!我要试一试。然而,我想知道,从字符位置(regex结果)到单词位置(列表索引)的映射到底会不会更容易。谢谢!“if”看起来很不错,但似乎不适用于,例如,句子=['as','long','as','It','will'。
[0, 4]
['if', 'it', 'will', 'rain', ',']