用于查找有效 Sphinx 字段的正则表达式
我正在尝试验证给sphinx的字段是否有效,但遇到了一些困难。
想象一下,有效的字段是猫、老鼠、狗、小狗。
有效的搜索示例包括:
- @猫 搜索词
- @(猫) 搜索词
- @(猫, 狗) 搜索词
- @猫 搜索词1 @狗 搜索词2
- @(猫, 狗) 搜索词1 @老鼠 搜索词2
所以,我想用正则表达式来找到上面例子中的猫、狗、老鼠这些词,并将它们与有效词汇表进行对比。
因此,像这样的查询:
@(山羊)
会产生一个错误,因为山羊不是一个有效的词。
我已经能够用这个正则表达式找到简单的查询,比如@猫: (?:@)([^( ]*)
但我还不知道怎么找到其他的。
我在使用python和django,不知道这是否有帮助。
6 个回答
这个pyparsing的解决方案和你发的答案逻辑差不多。它会先匹配所有的标签,然后再和已知的有效标签列表进行对比,把有效的标签从结果中去掉。最后,只有那些在去掉有效标签后还剩下的匹配项才会被报告为匹配。
from pyparsing import *
# define the pattern of a tag, setting internal results names for easy validation
AT,LPAR,RPAR = map(Suppress,"@()")
term = Word(alphas,alphanums).setResultsName("terms",listAllMatches=True)
sphxTerm = AT + ~White() + ( term | LPAR + delimitedList(term) + RPAR )
# define tags we consider to be valid
valid = set("cat mouse dog".split())
# define a parse action to filter out valid terms, and attach to the sphxTerm
def filterValid(tokens):
tokens = [t for t in tokens.terms if t not in valid]
if not(tokens):
raise ParseException("",0,"")
return tokens
sphxTerm.setParseAction(filterValid)
##### Test out the parser #####
test = """@cat search terms @ house
@(cat) search terms
@(cat, dog) search term @(goat)
@cat searchterm1 @dog searchterm2 @(cat, doggerel)
@(cat, dog) searchterm1 @mouse searchterm2
@caterpillar"""
# scan for invalid terms, and print out the terms and their locations
for t,s,e in sphxTerm.scanString(test):
print "Terms:%s Line: %d Col: %d" % (t, lineno(s, test), col(s, test))
print line(s, test)
print " "*(col(s,test)-1)+"^"
print
这样就得到了很不错的结果:
Terms:['goat'] Line: 3 Col: 29
@(cat, dog) search term @(goat)
^
Terms:['doggerel'] Line: 4 Col: 39
@cat searchterm1 @dog searchterm2 @(cat, doggerel)
^
Terms:['caterpillar'] Line: 6 Col: 5
@caterpillar
^
最后这段代码会帮你完成所有的扫描工作,只会给你找到的无效标签的列表:
# print out all of the found invalid terms
print list(set(sum(sphxTerm.searchString(test), ParseResults([]))))
输出:
['caterpillar', 'goat', 'doggerel']
为了匹配所有允许的字段,下面这个看起来有点复杂的正则表达式可以用:
@((?:cat|mouse|dog|puppy)\b|\((?:(?:cat|mouse|dog|puppy)(?:, *|(?=\))))+\))
它会按顺序返回这些匹配项:@cat
、@(cat)
、@(cat, dog)
、@cat
、@dog
、@(cat, dog)
、@mouse
。
这个正则表达式可以分解成以下几个部分:
@ # the literal character "@" ( # match group 1 (?:cat|mouse|dog|puppy) # one of your valid search terms (not captured) \b # a word boundary | # or... \( # a literal opening paren (?: # non-capturing group (?:cat|mouse|dog|puppy) # one of your valid search terms (not captured) (?: # non-capturing group , * # a comma "," plus any number of spaces | # or... (?=\)) # a position followed by a closing paren ) # end non-capture group )+ # end non-capture group, repeat \) # a literal closing paren ) # end match group one.
现在,如果你想找出任何无效的搜索,可以把上面的内容放在一个负向前瞻中:
@(?!(?:cat|mouse|dog|puppy)\b|\((?:(?:cat|mouse|dog|puppy)(?:, *|(?=\))))+\)) --^^
这样就能找到任何@
后面跟着无效搜索词(或者词组合)的情况。把它修改成也能匹配这些无效尝试,而不仅仅是指出它们,这样做也不算太难。
你需要动态生成(?:cat|mouse|dog|puppy)
这个部分,并把它放进正则表达式的其他静态部分里。这样做应该也不会太复杂。
我最后用了一种不同的方法,因为上面提到的都没用。首先,我用这个找到了像@cat这样的字段:
attributes = re.findall('(?:@)([^\( ]*)', query)
接着,我用这个找到了更复杂的字段:
regex0 = re.compile('''
@ # at sign
(?: # start non-capturing group
\w+ # non-whitespace, one or more
\b # a boundary character (i.e. no more \w)
| # OR
( # capturing group
\( # left paren
[^@(),]+ # not an @(),
(?: # another non-caputing group
, * # a comma, then some spaces
[^@(),]+ # not @(),
)* # some quantity of this non-capturing group
\) # a right paren
) # end of non-capuring group
) # end of non-capturing group
''', re.VERBOSE)
# and this puts them into the attributes list.
groupedAttributes = re.findall(regex0, query)
for item in groupedAttributes:
attributes.extend(item.strip("(").strip(")").split(", "))
然后,我检查了一下我找到的属性是否有效,并把它们(唯一地)添加到一个数组里:
# check if the values are valid.
validRegex = re.compile(r'^mice$|^mouse$|^cat$|^dog$')
# if they aren't add them to a new list.
badAttrs = []
for attribute in attributes:
if len(attribute) == 0:
# if it's a zero length attribute, we punt
continue
if validRegex.search(attribute.lower()) == None:
# if the attribute from the search isn't in the valid list
if attribute not in badAttrs:
# and the attribute isn't already in the list
badAttrs.append(attribute)
不过还是要感谢大家的帮助。我很高兴能得到这些支持!