2010-03-23 68 views
3

我有搜索字符串,类似一个波纹管:解析搜索字符串

energy food "olympics 2010" Terrorism OR "government" OR cups NOT transport 

,我需要用PHP5解析它来检测,如果内容属于下列任何集群:

  • AllWords阵列
  • AnyWords阵列
  • NotWords阵列

这些都是我所设定的规则:

  1. 如果有或之前或单词,或者属于 AnyWord引用的话后。
  2. 如果它有一个以前没有的词或引用的话它属于NotWords
  3. 如果有词之前0以上的多个空格或引用这句呢 属于AllWords。

所以,最终的结果应该是类似的东西:

AllWords: (energy, food, "olympics 2010") 
AnyWords: (terrorism, "government", cups) 
NotWords: (Transport) 

会是什么好办法做到这一点?

回答

4

如果你想用正则表达式来做到这一点,请注意,你的解析将在愚蠢的用户输入(用户,而不是输入=))上破坏。

我想尝试下面的正则表达式。

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仅支持修正长度表达式的后顾之忧,所以我没有办法解决这个问题,对不起。您可以使用\b(\w+|"[^"]+")\b来拆分输入,并手动解析结果数组。

+0

嗨Jens,\ b(\ w + |“[^”] +“)\ b解析输入似乎是一个很好的解决方案,因为正则表达式的限制,然后我可以使用for循环来看看后面或之后数组桶以查看是否存在NOT或OR并相应地执行操作。 – 2010-03-23 11:31:34

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
    • 这里哟你必须确定什么是无效的输入以及你如何解释它,即:
    • 'NOT Transport':搜索任何不包含Transport或者通知用户他还必须包含至少一个搜索词的东西?
    • 'OR energy':可以用combinator开头吗?
    • '食物或非能量':这是否意味着“寻找食物或任何不含能量的食物”,或者它是指“寻找食物而不是能量”,或者这不代表什么意思? (即抛出异常,返回false或诸如此类的东西)
  • testParseEmpty

然后,写测试一个接一个,并编写通过测试的简单解决方案。然后重构并做出正确的决定,然后再次运行,看看你是否仍然通过测试。 一旦测试通过并且代码被重构,然后编写下一个测试并重复该过程。当您发现特殊情况并重构代码以使其通过所有测试时添加更多测试。如果您打破测试,请备份并重新编写代码(不是测试!),以使其通过。

至于如何解决这个问题,可以看看preg_match,strtok,或者简单地循环访问字符串,并添加令牌。