2012-03-03 125 views
1

我正在解析推文,作为向数据库添加提醒的快捷方式。推文看起来像这样:如何获得正则表达式不匹配的数据?

$tweet = '#notes @username !high_priority [Project Name] Tweet content'; 

我使用以下正则表达式来获得#,@,!和[项目]

$match = preg_match_all('/(#\\w*[a-zA-Z_]+\\w*)|(!\\w*[a-zA-Z_]+\\w*)|(@\\w*[a-zA-Z_]+\\w*)|(\\[[^\\]]*\\])/i', 
    $tweet, 
    $matches); 

我想知道怎么也得剩下的“分享Tweet内容”,这样简化版,匹配正则表达式一切都应该被保存到一个变量。

而且,如果将鸣叫的东西更像是匹配顺序事:

$tweet = '@username Tweet content [Project Name] #notes !high_priority'; 

有谁知道该怎么做?

+1

你觉得'\ w'做什么?它与'[a-zA-Z]'几乎相同' – Vyktor 2012-03-03 21:30:32

+0

只需循环遍历所有匹配,然后在每个不以#,@,!开始的匹配中组成一个字符串。 &[ – Yaniro 2012-03-03 21:44:47

回答

2

将正则表达式匹配的文本替换为空字符串。剩下的是正则表达式没有匹配的东西。

+0

我正在使用: '$ content = preg_replace('/(#\\ w * [a-zA-Z _] + \\ w *)|(!\\ w * [a-zA-Z_ ] +(w *)|(@ \ w * [a-zA-Z _] + \\ w *)|(\\ [[^ \\]] * \\])/ i','', $ subject);' 然后只是修剪剩余的空白。 – 2012-03-04 11:28:11

0

使用preg_split而不是preg_match_all,那么您将获得所有组件之间的所有组件,作为Brent的答案的替代方法,它返回单个字符串。请注意,许多比赛可能是空的。

+0

我还使用'preg_match'来键入遍历匹配的答案,保存偏移量以检索数据而不复制任何字符串,但这对于此用例来说太重了。我猜想罗马有很多种方式。 – 2012-03-03 22:30:45

0

我还没有测试过这段代码,但我认为这个非正则表达式的想法可能对你更好。基本上你用空格分割字符串,然后解析每一块。这种方法意味着零件的订单无关紧要。

由于内容和项目可以跨越多个部分,但我认为我的代码应该可以处理该问题,所以它有点棘手。它还假定您每个推文只有一个hashtag,用户,项目和优先级。例如,如果会有多个hashtags,只需将它们放入一个数组而不是一个字符串。最后,它没有任何错误处理来检测/防止奇怪的事情发生。

这里是我的未经测试的代码:

$data = array(
    'hash' => '', 
    'user' => '', 
    'priority' => '', 
    'project' => '', 
    'content' => '' 
); 

$parsingProjectName = false; 
foreach(explode(' ', $tweet) as $piece) 
{ 
    switch(substr($piece, 0, 1)) 
    { 
     case '#': 
      $data['hash'] = substr($piece, 1); 
      break; 
     case '@': 
      $data['user'] = substr($piece, 1); 
      break; 
     case '!': 
      $data['priority'] = substr($piece, 1); 
      break; 
     case '[': 
      // Check if the project name is longer than 1 word 
      if(strpos($piece, -1) == ']') 
      { 
       $data['project'] = substr($piece, 1, -1); 
      } 
      else 
      { 
       // There will be more to parse in the next piece(s) 
       $parsingProjectName = true; 
       $data['project'] = substr($piece, 1) . ' '; 
      } 
      break; 
     default: 
      if($parsingProjectName) 
      { 
       // Are we at the end yet? 
       if(strpos($piece, -1) == ']') 
       { 
        // Yes we are 
        $data['project'] .= substr($piece, 1, -1); 
        $parsingProjectName = false; 
       } 
       else 
       { 
        // Nope, there is more 
        $data['project'] .= substr($piece, 1) . ' '; 
       } 
      } 
      else 
      { 
       // We aren't in the middle of parsing the project name, and this piece doesn't start with one of the special chars, so assume it is content 
       $data['content'] .= $piece . ' '; 
      } 
    } 
} 

// There will be an extra space on the end; remove it 
$data['content'] = substr($data['content'], 0, -1); 
+0

顺便说一句,您可能需要仔细检查我对substr的使用情况。我用它来检查第一个字符,最后一个字符,并抓住除了第一个或最后一个字符以外的所有内容。我希望它是有道理的和有效的:P – 2012-03-03 22:53:25

0

我认为你有一个错误在你的正则表达式,你使用\ W前[A-ZA-Z_],它看起来像你想匹配的空白,而\ w匹配字字符。你可以这样做的(对于这个小区域):

...\\s*[\\w_]+\\s*... 

正如你似乎已经循环了比赛,以获得不同的部分,你可以创建你想要的纯文本的子模式匹配和或连接它与你的模式的其余部分。这样你只需要一次追加比赛。只要您在循环匹配时区分匹配的部分,这将适用于内容的不同顺序。