我的
preg_match()
代码遇到一些问题。
$text = "tel: 012 213 123. mobil: 0303 11234 \n address: street 14";
$regex_string = '/(tel|Tel|TEL)[\s|:]+(.+)[\.|\n]/';
preg_match($regex_string , $text, $match);
我在 $match[2] 中得到这个结果
"012 213 123. mobil: 023 123 123"
第一个问题:
我希望正则表达式停在
.
(点)处,但事实并非如此。
有人可以解释一下为什么不是吗?
第二个问题:
preg_match 使用 () 来获取匹配项。
是否可以跳过不同“电话”周围的括号并仍然获得相同的功能?
这应该做:
/tel(?:\s|:)+([^.]+)(?:\.|$)/i
+
是一个贪婪量词,这意味着它将匹配尽可能多的字符。
对于你的第二个问题:在这种特殊情况下,你只需要使用不区分大小写的匹配(
i
标志)。一般来说,您可以使用 (?:...)
语法,您可以在最终匹配中看到其示例。方括号用于字符类。
如果您只是想从该行中提取电话号码,并且保证是 11 个号码,则可以简单地使用以下命令:
$text = 'tel: 012 213 123. mobil: 0303 11234';
$phone_number = substr(preg_replace('/[^\d]/', '', $text), 0, 11);`
以您的示例为例,
$phone_number
将是0122131230
。
其工作原理是将任何非数字替换为空字符串,将其删除,然后返回前 11 个数字。
不知道 - 你的正则表达式对我有用(我用你的代码在
$match[2]
中得到“012 213 123”)。两者之间的手机不同这一事实可能表明它实际上并不是代码的输出;再检查一下。
其他一些事情 - 如果行中碰巧有更多点(例如“电话:xxx。电话:xxx。传真:xxx”),你会得到不好的结果 - 使用非贪婪运算符(“获取最少的块”匹配”
.*?
而不是“获取匹配的最大块” .*
)或限制重复字符(“任意数量的非句点” [^.]*
)。另外,您可以通过使正则表达式不区分大小写来省去麻烦(除非您真的讨厌人们输入“tEl”)。
您的另一个问题:
(?:stuff)
将像(stuff)
一样匹配“东西”,但不会捕获它。
为什么你的角色类中有管道
[\.|\n]
和 [\s|:]
?字符类(方括号中的内容[]
)根据定义类似于 OR 关系,因此您不需要管道...除非您确实想匹配管道|
。
对于问题#1,我不确定你的问题是什么,但这通常与贪婪量词有关。
(.+)
量词是贪婪的,因此它会尽可能多地匹配,同时仍然匹配整个模式。贪婪量词不关心模式中它们后面的内容。由于句点 .
匹配除换行符之外的任何字符,因此它可以匹配句点,因此它确实匹配句点。要使量词变得非贪婪,您可以使用问号 ?
。
对于你的第二个问题,在正则表达式中使用括号对事物进行分组并存储它们。如果您想对
(tel|Tel|TEL)
进行分组,但不将其存储在 $match
中,您可以在左括号后面添加 ?:
:
(?:tel|Tel|TEL)
您的意思是您只想匹配数字,这样您就不必去掉
tel:
和点吗? 试试这个:
/tel[:\s]+\K[^.]+/i
i
使其不区分大小写。
[:\s]
匹配冒号或空格(|
在字符类中并不表示“或”,它只匹配 |
)。
[^.]+
匹配一个或多个非点;当它看到一个点或行尾时,它会停止匹配,因此如果您不希望它出现在结果中,则不必匹配该点。
最后,
\K
的意思是“忘记到目前为止你所匹配的任何内容,假装比赛真正从这里开始”——这是一个仅在 Perl 和 PHP 中可用的功能(据我所知)。
要删除字符串中不需要的部分,请使用
preg_replace()
。
tel
单词,i
允许匹配 tel
不区分大小写,并且 s
允许 .
除了所有其他字符之外还匹配换行符。
代码:(演示)
$text = "tel: 012 213 123. mobil: 0303 11234 \n address: street 14";
echo preg_replace(
'/tel\D*(\d+(?: \d+)*).*/is',
'$1',
$text
);
// 012 213 123