【问题标题】:parse search string解析搜索字符串
【发布时间】:2011-01-30 17:55:14
【问题描述】:

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

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

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

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

这些是我制定的规则:

  1. 如果它在单词或引用的单词之前或之后有 OR 如果属于 AnyWord。
  2. 如果它在单词或引用的单词之前有一个 NOT,则它属于 NotWords
  3. 如果在单词或引用短语之前有 0 个或多个空格,则 属于 AllWords。

所以最终结果应该类似于:

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

什么是这样做的好方法?

【问题讨论】:

    标签: php regex parsing


    【解决方案1】:

    如果您想使用 Regex 执行此操作,请注意您的解析将在愚蠢的用户输入(用户,而不是输入 =))上中断。

    我会尝试以下正则表达式。

    NotWords:

    (?<=NOT\s)\b((?!NOT|OR)\w+|"[^"]+")\b
    

    全词:

    (?<!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)
    (?<!OR\s)\b((?!NOT|OR)\w+|"[^"]+")\b(?=\s+OR)
    

    问题:这些在修饰词和表达式之间需要一个空格。 PHP 只支持lookbehinds 来修复长度表达式,所以我看不出有什么办法,抱歉。您可以只使用\b(\w+|"[^"]+")\b 来拆分输入,然后手动解析结果数组。

    【讨论】:

    • Hi Jens, \b(\w+|"[^"]+")\b 解析输入似乎是一个很好的解决方案,因为正则表达式的限制,然后我可以使用 for 循环查看数组存储桶的后面或后面,看看是否有 NOT 或 OR 并采取相应措施。
    【解决方案2】:

    这是一个很好的例子,说明测试优先驱动方法如何帮助您找到解决方案。它可能不是最好的,但是编写测试可以让您自信地重构并立即查看是否破坏了任何现有测试。无论如何,您可以设置一些测试,例如:

    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':可以从组合子开始吗?
      • 'food OR NOT energy':这是指“寻找食物或任何不含能量的东西”,还是意味着“寻找食物而不是能量”,还是什么都没有? (即抛出异常,返回 false 或诸如此类)
    • testParseEmpty

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

    至于如何解决此问题,请查看preg_matchstrtok 或简单地通过字符串循环添加标记。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      相关资源
      最近更新 更多