我正在研究这个小代码。我设法让它在一侧使用双引号,但在另一侧则不工作:
/(?<!S)#([0-9p{L}]+)+(?=[s,!?.n][^"]|$)/
我的意思是:https://regex101.com/r/yN4tJ6/307
最后一个" #action
不应该转换为主题标签。如何将此函数添加到上面的代码中?
这个表达式似乎有效:
(?<!S)(?<!".)#([0-9p{L}]+)+(?=[s,!?.n][^"]|$)
演示
我的猜测是,您可能希望设计一个类似于以下内容的表达式:
(?<!"s)#([0-9p{L}]+)(?=[s,!?.n][^"]|$)
如果您希望探索/简化/修改表达式,可以在 regex101.com 的右上角面板上解释该表达式,在此链接中,如果您愿意,可以查看它如何与一些示例输入匹配。
测试
$re = '/(?<!"s)#([0-9p{L}]+)(?=[s,!?.n][^"]|$)/m';
$str = 'I enjoy #action movies! #Action
movies are #cool.
Color #000000; #ffffff; work fine
<div style=" #something "> - works
#action " - works
" #action - doesn't work
';
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
var_dump($matches);
您当前模式的问题几乎有效,您需要一个可变宽度的后视来正确检查每个主题标签之前是否存在双引号。 我采取的方法是将preg_match_all
与一种模式一起使用,该模式仅消耗足够的信息来决定主题标签是否匹配。 请考虑以下脚本:
preg_match_all('/(?:^|[^"]s+)(#[0-9p{L}]+)[.;,!?]?(?=$|s+[^"])/', $input, $matches);
print_r($matches[1]);
Array
(
[0] => #action
[1] => #Action
[2] => #cool
[3] => #000000
[4] => #ffffff
)
以下是该模式的说明:
(?:^|[^"]s+) match the start of the input, OR
a single non quote character, followed by one or more whitespaces
(#[0-9p{L}]+) then match and capture a hashtag
[.;,!?]? followed by an optional punctuation character
(?=$|s+[^"]) finally lookahead and assert either the end of the input, OR
one or more whitespaces followed by a single non quote character
请注意,虽然我们确实匹配了一些我们并不真正想要的内容,但这并不重要,因为第一个捕获组仅包含主题标签。