我有搜索字符串,类似于下面的字符串:
energy food "olympics 2010" Terrorism OR "government" OR cups NOT transport
我需要用PHP5解析它以检测内容是否属于以下任何集群:
这些是我设定的规则:
所以最终结果应该类似于:
AllWords: (energy, food, "olympics 2010")
AnyWords: (terrorism, "government", cups)
NotWords: (Transport)
这样做的好方法是什么?
答案 0 :(得分:4)
如果您想使用Regex执行此操作,请注意您的解析将在愚蠢的用户输入(用户,而不是输入=)上中断。
我会尝试以下正则表达式。
NotWords:
(?<=NOT\s)\b((?!NOT|OR)\w+|"[^"]+")\b
AllWords:
(?<!OR\s)\b((?!NOT|OR)\w+|"[^"]+")\b(?!\s+OR)
AnyWords: 嗯......其余的。 =)它们并不容易被发现,因为我不知道如何将“OR在它后面或OR前面”放到正则表达式中。也许你可以加入三个正则表达式的结果
(?<=OR\s)\b((?!NOT|OR)\w+|"[^"]+")\b(?!\s+OR)
(?<=OR\s)\b((?!NOT|OR)\w+|"[^"]+")\b(?=\s+OR)
(?<!OR\s)\b((?!NOT|OR)\w+|"[^"]+")\b(?=\s+OR)
问题:修饰词和表达式之间只需要一个空格。 PHP只支持修复长度表达式的lookbehinds,所以我认为没办法,抱歉。您可以使用\b(\w+|"[^"]+")\b
拆分输入,并手动解析生成的数组。
答案 1 :(得分:3)
这是测试优先驱动方法如何帮助您找到解决方案的一个很好的例子。它可能不是最好的,但是编写测试可以让您自信地进行重构,并立即查看是否中断了任何现有测试。无论如何,你可以设置一些测试,如:
public function setUp () {
$this->searchParser = new App_Search_Parser();
}
public function testSingleWordParsesToAllWords () {
$this->searchParser->parse('Transport');
$this->assertEquals(
$this->searchParser->getAllWords(),
array('Transport')
);
$this->assertEquals($this->searchParser->getNotWords(), array());
$this->assertEquals($this->searchParser->getAnyWords());
}
public function testParseOfCombinedSearchString () {
$query = 'energy food "olympics 2010" Terrorism ' .
'OR "government" OR cups NOT transport';
$this->searchParser->parse($query);
$this->assertEquals(
$this->searchParser->getAllWords(),
array('energy', 'food', 'olympics 2010')
);
$this->assertEquals(
$this->searchParser->getNotWords(),
array('Transport')
);
$this->assertEquals(
$this->searchParser->getAnyWords(),
array( 'terrorism', 'government', 'cups')
);
}
其他好的测试包括:
testParseTwoWords
testParseTwoWordsWithOr
testParseSimpleWithNot
testParseInvalid
testParseEmpty
然后,逐个编写测试,并编写一个通过测试的简单解决方案。然后重构并使其正确,然后再次运行以确定您仍然通过了测试。 一旦测试通过并且代码被重构,则编写下一个测试并重复该过程。在找到特殊情况时添加更多测试并重构代码,以便它通过所有测试。如果你打破了测试,请备份并重新编写代码(而不是测试!),以便它通过。
至于如何解决这个问题,请查看preg_match,strtok或依靠循环遍历字符串添加令牌。