0

我正在尝试匹配半动态生成的字符串。所以我可以看看它的格式是否正确,然后从中提取我需要的信息。我的问题是,无论我多么努力地掌握正则表达式,我都无法终生理解它。即使在所谓的生成器的帮助下。

我有几个不同的字符串,如下所示。[@img:1234567890][@user:1234567890][@file:file_name-with.ext]。像这样的字符串 pass through 旨在通过过滤器,因此它们可以被链接替换,或者更易读的名称。但是再试一次,我可能无法为其中任何一个想出一个正则表达式。

我正在寻找格式:[@word:]我将从字符串中删除 [、]、@ 和单词,这样我就可以相应地对我的数据库进行查询,无论它是什么,并相应地使用它。只是正则表达式位阻碍了我。

4

3 回答 3

1

这就是我要做的。

<pre>
<?php

    $subj = 'An image:[@img:1234567890], a user:[@user:1234567890] and a file:[@file:file_name-with.ext]';
    preg_match_all('~(?<match>\[@(?<type>[^:]+):(?<value>[^\]]+)\])~',$subj,$matches,PREG_SET_ORDER);
    foreach ($matches as &$arr) unset($arr[0],$arr[1],$arr[2],$arr[3]);
    print_r($matches);

?>
</pre>

这将输出

Array
(
    [0] => Array
        (
            [match] => [@img:1234567890]
            [type] => img
            [value] => 1234567890
        )

    [1] => Array
        (
            [match] => [@user:1234567890]
            [type] => user
            [value] => 1234567890
        )

    [2] => Array
        (
            [match] => [@file:file_name-with.ext]
            [type] => file
            [value] => file_name-with.ext
        )

)

这是我如何使用该preg_replace_callback()函数的伪版本:

function replace_shortcut($matches) {
    global $users;
    switch (strtolower($matches['type'])) {
        case 'img'  : return '<img src="images/img_'.$matches['value'].'jpg" />';
        case 'file' : return '<a href="files/'.$matches['value'].'" target="_blank">'.$matches['value'].'</a>';
        // add id of each user in array
        case 'user' : $users[] = (int) $matches['value']; return '%s';
        default : return $matches['match'];
    }
}

$users = array();
$replaceArr = array();

$subj = 'An image:[@img:1234567890], a user:[@user:1234567890] and a file:[@file:file_name-with.ext]';
// escape percentage signs to avoid complications in the vsprintf function call later
$subj = strtr($subj,array('%'=>'%%'));
$subj = preg_replace_callback('~(?<match>\[@(?<type>[^:]+):(?<value>[^\]]+)\])~',replace_shortcut,$subj);

if (!empty($users)) {

    // connect to DB and check users
    $query = "  SELECT `id`,`nick`,`date_deleted` IS NOT NULL AS 'deleted'
                FROM `users` WHERE `id` IN ('".implode("','",$users)."')";
    // query
    // ...
    // and catch results
    while ($row = $con->fetch_array()) {
        // position of this id in users array:
        $idx = array_search($row['id'],$users);
        $nick = htmlspecialchars($row['nick']);
        $replaceArr[$idx] = $row['deleted'] ?
            "<span class=\"user_deleted\">{$nick}</span>" :
            "<a href=\"users/{$row['id']}\">{$nick}</a>";
        // delete this key so that we can check id's not found later...
        unset($users[$idx]);
    }
    // in here:
    foreach ($users as $key => $value) {
        $replaceArr[$key] = '<span class="user_unknown">User'.$value.'</span>';
    }
    // replace each user reference marked with %s in $subj
    $subj = vsprintf($subj,$replaceArr);

} else {

    // remove extra percentage signs we added for vsprintf function
    $subj = preg_replace('~%{2}~','%',$subj);

}
unset($query,$row,$nick,$idx,$key,$value,$users,$replaceArr);

echo $subj;
于 2012-10-07T02:10:16.687 回答
1

不知道你说的发电机是什么意思。我总是使用在线匹配器来查看我的测试用例是否有效。@Virendra 几乎拥有它,除了忘记逃避字符[]

/\[@(\w+):(.*)\]/

您需要以正则表达式分隔符开始和结束,在本例中为“/”字符。

然后我们转义正则表达式使用的'[]'来匹配字符范围,因此是'['。

接下来我们匹配一个文字“@”符号。

现在我们要保存下一场比赛,以便我们以后可以使用它,所以我们用().

\w匹配一个word. 基本上任何不是空格、标点符号或行字符的字符。

再次匹配文字:

将第二部分放在匹配组中可能很有用,因此(.*)可以多次匹配任何字符,并为您保存。

]然后我们像之前所做的那样逃避关闭。

由于听起来您想稍后在查询中使用匹配项,我们可以使用preg_match将匹配项保存到数组中。

$pattern = '/\[@(\w+):(.*)\]/';
$subject = '[@user:1234567890]';
preg_match($pattern, $subject, $matches);
print_r($matches);

会输出

array(
    [0] => '[@user:1234567890]', // Full match
    [1] => 'user', // First match
    [2] => '1234567890' // Second match
)

我发现一个特别有用的工具是txt2re

于 2012-10-07T00:25:14.193 回答
0

你可以尝试这样的事情:

/\[@(\w+):([^]]*)\]/

\[转义[字符(否则解释为字符集);\w表示任何“单词”字符,并[^]]*表示任何非]字符(为了避免匹配超过标签的末尾,.*可能)。parens 对各种匹配的部分进行分组,以便您可以使用$1and $2inpreg_replace来生成替换文本:

echo preg_replace('/\[@(\w+):([^]]*)\]/', '$1 $2', '[@link:abcdef]');

印刷link abcdef

于 2012-10-07T00:25:32.690 回答