如何获取正则表达式所做的数据;t匹配


How do I get data a regular expression does't match?

我正在分析一条推文,将其作为向数据库添加提醒的快速方法。推特看起来像这样:

$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';

有人知道怎么做吗?

将正则表达式匹配的文本替换为空字符串。剩下的是正则表达式不匹配的内容。

我还没有测试过这段代码,但我认为这种非正则表达式的想法可能更适合您。从本质上讲,您可以用空格分割字符串,然后解析每一部分。这种方法意味着零件的顺序无关紧要。

这有点棘手,因为内容和项目可以跨越多个部分,但我认为我的代码应该处理好这一点。它还假设每条推文只有一个标签、用户、项目和优先级。例如,如果有多个标签,只需将它们放在一个数组中,而不是字符串中。最后,它没有任何错误处理来检测/防止奇怪的事情发生。

这是我未经测试的代码:

$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);

使用preg_split而不是preg_match_all,然后获得介于两者之间的所有组件,作为Brent返回单个字符串的答案的替代方案。请注意,许多匹配项可能为空。

我认为在[a-zA-Z_]之前使用''w时,您的RegEx中出现了一个错误,看起来您想要匹配空白,而''w匹配单词字符。你可以这样做(对于这个小部分):

...''s*[''w_]+''s*...

由于您似乎已经在匹配中循环以获得不同的部分,因此可以为要匹配的纯文本创建一个子模式,或者将其与模式的其余部分连接。这样一来,你只需要再打一场比赛。只要在循环匹配的同时区分匹配的部分,这也适用于不同的内容顺序。