检测字符串中的@mentions 从一个匹配项中返回两个元素

Posted

技术标签:

【中文标题】检测字符串中的@mentions 从一个匹配项中返回两个元素【英文标题】:Detecting @mentions in a string returns two elements from one match 【发布时间】:2014-06-09 16:39:33 【问题描述】:

我有以下代码:

$string = "Manual balls knit cardigan @120rb

ORDER
BB 28AFF6A6 atau 25AE5DB3 
Phone 081298249949 atau 081310570229 
Line indy2212 atau indy2281 
FORMAT
Nama 
Alamat 
Telp 
Kode barang";

if (preg_match('/(?<= )@([^@ ]+)/', $string, $matches)) 
    var_dump(count($matches));
    var_dump('first ' . $matches[0]);
    var_dump('second ' . $matches[1]);

但是,这会导致 $matches 返回计数为 2 的数组。使用以下字符串:

2
@120rb ORDER BB
120rb ORDER BB

我的问题是为什么?为什么它匹配字符串两次?我的正则表达式有什么问题

【问题讨论】:

第一个元素是整个匹配,也就是 $0,而第二个元素是第一个内存捕获,也就是 $1。 @mickmackusa 好点,@[^@\s]+would be better。我已经删除了原来的评论。 【参考方案1】:

preg_match() 将匹配项存储到您作为第三个参数提供的数组中。在这种情况下,您的 preg_match() 语句如下所示:

preg_match('/(?<= )@([^@ ]+)/', $string, $matches);

所以$matches 包含所有匹配项,其中:

$matches[0] 将包含与完整模式匹配的文本 $matches[1] 将具有与第一个捕获组匹配的文本 $matches[2] 将具有与第二个捕获组匹配的文本 等等……

这里的正则表达式是(?&lt;= )@([^@ ]+)。它完全匹配@120rb ORDER BB,所以它会存储在$matches[0],而捕获组([^@ ]+)只会捕获@120rb ORDER BB)之后的部分,它将存储在$matches[1]

目前,正则表达式不检测提及是否在字符串的开头。此外,它会错误地匹配下一行的空格,因为[^@] 将匹配任何不是@ 符号的东西。我会在preg_match_all() 中使用以下表达式:

(?<=^|\s)@([^@\s]+)

代码:

if (preg_match_all('/(?<=^|\s)@([^@\s]+)/', $string, $matches)) 
    print_r($matches[1]);

要获得匹配的数量,你可以使用echo count($matches[0]);

Demo

【讨论】:

那么我该如何更改它以便我想跟踪我的字符串中有多少提及? @adit count($matches[0]). @adit 您可以将您的字符串 + 正则表达式发布到 regex101.com 并发送一个永久链接(点击左侧的软盘)吗?【参考方案2】:

preg_match()preg_match_all() 都允许将引用变量赋值为它们的第三个参数。如果您提供变量,则默认行为是将全字符串匹配项放在其第一个元素中。

当您只想提取模式的完整字符串匹配的最后一部分时,可以使用\K 丢弃前导/不需要的字符。这避免了后视的费用。

preg_match()preg_match_all() 都提供找到的全字符串匹配的数量作为它们的返回值。这意味着永远不需要在matches数组上调用count()

我下面的模式会匹配字符串的起始位置(^)或空白字符(\s),然后匹配文字@符号,然后忘记这些匹配的字符,然后匹配一个或多个“单词字符”,由字母、数字和下划线组成。此模式应消除错误匹配,例如电子邮件地址和未提及。

如果您需要确保提及后不会立即出现无效字符,您可以在模式的末尾写一个前瞻来要求字符串的结束位置或空白字符 ((?=$|\s))。

代码:(Demo)

$string = '@mention_1 @$badmention Manual balls knit cardigan @120rb
email me @ example@example.com';

$count = preg_match_all(
    '/(?:^|\s)@\K\w+/',
    $string,
    $matches
);

var_export([
    'count' => $count,
    'matches' => $matches[0]
]);

输出:

array (
  'count' => 2,
  'matches' => 
  array (
    0 => 'mention_1',
    1 => '120rb',
  ),
)

【讨论】:

以上是关于检测字符串中的@mentions 从一个匹配项中返回两个元素的主要内容,如果未能解决你的问题,请参考以下文章

检测项中的静态库是否使用UIWebView

导航滚动到列表项中的匹配元素

如何从熊猫数据框中的字符串项中删除数字

使用正则表达式从python中的列表项中删除子字符串

用Python正则表达式从一个匹配项中打印出2个项目。

PHP Regex preg_replace 函数仅查找和替换 3 个匹配项中的第一个和最后一个,而不是中间一个