2016-11-02 54 views
1

首先,这是作业。 (我不能在标题中使用标签,底部的标签列表中没有任何内容出现在作业中,所以请让我知道是否应该编辑其他有关此问题的内容)。Python正则表达式匹配带重复辅音的单词

所以我一直在阅读python文档和清理SO,发现几个解决方案接近我想要的,但不是确切的。

我有我读了一个字符串的字典:

a 
aa 
aabbaa 
... 
z 

我们在这练习的数据正则表达式的各种patters。 这里的具体问题是返回匹配模式的单词列表,而不是每个匹配组中的元组。

例如:

鉴于本字典一样的一个子集:

someword 
sommmmmeword 
someworddddd 
sooooomeword 

我要回:

['sommmmmword', 'someworddddd'] 

NOT:

[('sommmmword', 'mmmmm', ...), ...] # or any other variant 

编辑:

我的推理背后的上述例子,是我想看看我可以如何避免第二次通过结果。这是不是说:

res = re.match(re.compile(r'pattern'), dictionary) 
return [r[0] for r in res] 

我特别想要一个机制,我可以只使用:

return re.match(re.compile(r'pattern'), dictionary) 

我知道这听起来可能很傻,但我这样做是为了真正深入到正则表达式。我在底部提到这一点。

这是我曾尝试:

# learned about back refs 
r'\b([b-z&&[^eiou]])\1+\b' -> # nothing 

# back refs were weird, I want to match something N times 
r'\b[b-z&&[^eiou]]{2}\b' -> # nothing 

某处在测试中,我发现一个模式返回之类的东西'\nsomeword'。我无法弄清楚它是什么,但如果我再次找到该模式,我会在这里包括它的完整性。

# Maybe the \b word markers don't work how I think? 
r'.*[b-z&&[^eiou]]{2}' -> # still nothing 

# Okay lets just try to match something in between anything 
r'.*[b-z&&[^eiou]].*' -> # nope 

# Since its words, maybe I should be more explicit. 
r'[a-z]*[b-z&&[^eiou]][a-z]*' -> # still nope 

# Decided to go back to grouping. 
r'([b-z&&[^eiou]])(\1)' # I realize set difference may be the issue 

# I saw someone (on SO) use set difference claiming it works 
# but I gave up on it... 

# OKAY getting close 
r'(([b-df-hj-np-tv-xz])(\2))' -> [('ll', 'l', 'l'), ...] 

# Trying the the previous ones without set difference 
r'\b(.*(?:[b-df-hj-np-tv-xz]{3}).*)\b' -> # returned everything (all words) 

# Here I realize I need a non-greedy leading pattern (.* -> .*?) 
r'\b(.*?(?:[b-df-hj-np-tv-xz]{3}).*)\b' -> # still everything 

# Maybe I need the comma in {3,} to get anything 3 or more 
r'\b(.*?(?:[b-df-hj-np-tv-xz]{3,}).*)\b' -> # still everything 

# okay I'll try a 1 line test just in case 
r'\b(.*?([b-df-hj-np-tv-xz])(\2{3,}).*)\b' 
    # Using 'asdfdffff' -> [('asdfdffff', 'f', 'fff')] 
    # Using dictionary -> [] # WAIT WHAT?! 

这最后一个是如何工作的?也许有没有3+重复辅音字?我在我的学校服务器上使用了/usr/share/dict/cracklib-small,我认为这个服务器大约有50,000个字。

我仍在努力,但任何建议都会很棒。

我觉得好奇的一件事是,你不能回引用一个非捕获组。如果我只想输出完整的单词,我使用(?:...)来避免捕获,但是我无法取回参考。很明显,我可以离开捕捉,循环播放结果和过滤掉额外的东西,但我绝对想用只有正则表达式来解决这个问题!

也许有办法做非捕获,但仍然允许回参考?或者也许有一个完全不同的表达,我还没有测试过。

+0

作业是细问这里的时候,你有这方面所作的努力:)请分享'['sommmmmword','someworddddd']'而不是'[('sommmmword','mmmmm',...),...]的逻辑'这些两者的区别是什么? ? –

+0

啊,是的,抱歉,如果这似乎令人困惑。我进行了编辑。 – spanishgum

+0

1)使用're.findall'获取所有结果,而不是're.match'(只搜索1个匹配项,只在字符串开始处)。 2)'[b-z && [^ eiou]]'是一个Java/ICU正则表达式,Python're'不支持这种语法。 3)为了避免使用're.findall'的元组中的“额外”值,*不要*使用捕获组。如果您需要反向引用,请使用're.finditer'而不是're.findall'并访问每个匹配的'.group()'。 –

回答

1

这里有几点考虑:

  1. 使用re.findall把所有的结果,而不是re.match(仅搜索1个匹配,只有在字符串的开始)。

  2. [b-z&&[^eiou]]是Java/ICU正则表达式,Python re不支持此语法。在Python中,您可以重新定义范围以跳过元音,或使用(?![eiou])[b-z]

  3. 为避免元组中带有re.findall,的元组中的“额外”值,请勿使用使用捕获组。如果您需要反向引用,请使用re.finditer而不是re.findall并访问每个匹配的.group()

说回正题,你怎么可以使用反向引用,仍然获得了全场比赛,这里是一个working demo

import re 
s = """someword 
sommmmmeword 
someworddddd 
sooooomeword""" 
res =[x.group() for x in re.finditer(r"\w*([b-df-hj-np-tv-xz])\1\w*", s)] 
print(res) 
# => ['sommmmmeword', 'someworddddd'] 
+0

啊,我正在使用fiindall,我只是误输了这个例子。但我没有尝试finditer!我认为这只是findall的一个生成器。一旦我回家,我会试一试!谢谢。另外作为一个附注,不是明确地说'\ 1 \ 1 \ 1 \ 1 ...'来收集匹配的N个副本,我可以只使用\ 1 {N}而不分组吗? – spanishgum

+0

您可以使用与反向引用相同的量词(=量化反向引用),方法与任何原子相同:'\ 1 {4}'。看[这个正则表达式演示](https://regex101.com/r/FU9R61/1)。 –