解析搜索字符串

时间:2010-03-23 10:41:53

标签: php regex parsing

我有搜索字符串,类似于下面的字符串:

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

我需要用PHP5解析它以检测内容是否属于以下任何集群:

  • AllWords数组
  • AnyWords数组
  • NotWords数组

这些是我设定的规则:

  1. 如果在单词或引用单词之前或之后有OR,则属于 AnyWord。
  2. 如果它在单词或引用单词之前有NOT,则它属于NotWords
  3. 如果它在单词或引用短语之前有0或更多空格 属于AllWords。
  4. 所以最终结果应该类似于:

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

    这样做的好方法是什么?

2 个答案:

答案 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
    • 在这里你必须决定什么是无效输入以及你如何解释它,即:
    • 'NOT Transport':搜索任何不包含Transport的内容或通知用户他还必须包含至少一个搜索字词?
    • 'OR energy':从组合器开始可以吗?
    • '食物或非能量':这是否意味着“寻找食物或任何不含能量的物质”,或者它是指“寻找食物而不是能量”,或者它是否意味着什么? (即抛出异常,返回虚假或诸如此类的东西)
  • testParseEmpty

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

至于如何解决这个问题,请查看preg_matchstrtok或依靠循环遍历字符串添加令牌。