PHP正则表达式中的或操作:掌握preg_match()函数与模式匹配技巧

在PHP的正则表达式世界里,“或”操作是一个非常重要且常用的概念。它允许我们匹配多个可能的模式中的一个,这在处理各种复杂的文本处理场景中起到了关键作用。

PHP正则表达式基础回顾

我们得先对PHP正则表达式有个基本的认识。在PHP里,我们主要是通过preg_match()等函数来使用正则表达式的。比如我们想简单地匹配一个字符串里是否有数字,我们可以这样做:


$string = "abc123def";
if (preg_match('/\d/', $string)) {
    echo "字符串中包含数字";
}

这里/\d/就是一个基本的正则表达式模式,用来匹配一个数字。\(\d\)在正则里就是数字的快捷表示方式,类似的还有\(\w\)表示字母数字下划线等。

“或”操作的基本表示方式

在PHP正则中,“或”有两种主要的表示方式。

(一)竖线(|)

最常见的方式就是使用竖线|来表示“或”。例如,我们想要匹配一个字符串里要么是“apple”要么是“banana”。代码如下:


$string1 = "I have an apple.";
$string2 = "She likes banana.";
$pattern = '/apple|banana/';
if (preg_match($pattern, $string1)) {
    echo "在字符串1中匹配到apple或者banana";
}

这里的模式/apple|banana/就表示既可以匹配“apple”也可以匹配“banana”。使用这个的时候有几个小问题要注意。

问题1:匹配范围问题

假设我们有像/a|b/这样的模式去匹配字符串“abc”,它会只匹配到第一个字符“a”,而不是整个“ab”或者“abc”。因为正则表达式默认是尽可能少地去匹配(这个叫最小匹配或者叫懒匹配)。如果我们想要匹配到尽可能长的符合模式的字符串,我们可能需要使用/a.<b>|b.</b>/这种方式(这里的.*表示匹配任意字符零个或多个)。

问题2:优先级问题

如果我们的“或”表达式比较复杂,比如/(abc|def)ghi|jkl/,这里就存在一个优先级问题。圆括号是用来分组的,这个表达式会先尝试匹配(abc|def)ghi这个组,如果这个组合体匹配不成功,才会去尝试匹配jkl。为了清晰起见,我建议在复杂的表达式里面多使用圆括号来明确你的逻辑分组。

(二)字符类(中括号 [])里的表示

在字符类里,我们其实也可以表示一种“或”的概念。例如,我们想匹配一个字符既可以是元音字母“a”“e”“i”“o”“u”中的任何一个,我们可以使用/[aeiou]/。这种方式本质上也是一种“或”,只是限定在单个字符的匹配上。

不过这里也有一些容易犯的错误。比如,如果你想匹配“abc”或者“acd”,你可能会错误地写成/[abc]|[acd]/,这种写法是不正确的,因为它会匹配“a”“b”“c”或者“a”“c”“d”这单个的字符,而不是整个的“abc”或者“acd”。正确的写法应该是/(abc|acd)/

应用场景

(一)日志分析项目中的应用

想象一下我们在做一个项目,专门用来分析服务器的日志文件。日志文件里可能有不同类型的访问记录,比如来自网页的访问日志(可能包含关键词“http”等)和来自内部服务的访问日志(可能包含关键词“rpc”等)。我们想要把这两类不同来源的日志摘出来做不同的处理。

我们假设日志文件的每一行是一个单独的字符串。下面是一个简单的代码示例:


$logLines = array(
    "2023 - 09 - 01 10:00:00 http://example.com/page1 - status 200",
    "2023 - 09 - 01 10:05:00 rpc - call to service1 - success",
);
foreach ($logLines as $line) {
    $pattern = '/http|rpc/';
    if (preg_match($pattern, $line)) {
            // 处理网页访问日志

echo "这是网页访问日志: ". $line. " "; } else { } } }

在这里,我们先通过/http|rpc/这个模式找出可能是我们感兴趣的日志行,然后再进一步通过单独的/http/或者相关的内部服务关键词检测来区分到底是哪种日志类型。当然,这个例子只是一个非常基础的示例,在实际的日志分析项目中,可能还需要更复杂的正则表达式来准确地匹配和处理数据。例如,要精确匹配各种不同协议下的网页访问,像https?://(这个表达式用来匹配“http://”或者“https://”),我们可能需要更新我们的模式为/https?://|rpc/

(二)用户输入验证

在一个用户注册或者登录系统里面,我们往往需要验证用户的输入。比如对于用户输入的用户名,我们可能希望用户名只能包含字母、数字或者下划线。我们就可以使用正则表达式来验证。


$username = "user_name123";
$validPattern = '/^[\w]+$/'; // ^表示开头,$表示结尾,这个表达式表示整个字符串必须由字母数字下划线组成
if (preg_match($validPattern, $username)) {
    echo "用户名有效";
} else {
}
// 但是如果我们想要允许用户名也可以有中文字符,我们就需要修改模式。假设我们允许中英文、数字和下划线
$newValidPattern = '/^[\u4e00-\u9fff\w]+$/'; // 这里的 \u4e00-\u9fff 用来匹配中文字符范围
$newUsername = "李四user_name123";

if (preg_match($newValidPattern, $newUsername)) { echo "新用户名有效"; } else { }

这里虽然不是直接的“或”操作情况,但是如果我们从字符类的角度看,这里也是一种广义的“或”,就是这个字符可以是中文字母、英文字母、数字或者下划线中的一种。我们还可以进一步设想这样一种情况,如果我们想要允许用户名中还可以使用某些特殊字符,比如“ - ”或者“.”(当然这在安全方面和设计方面需要谨慎考虑),我们的模式就可以修改为/^[\u4e00 - \u9fff\w\-.]+$/,这里对于特殊字符“ - ”,因为它在字符类中有特殊含义(表示范围,比如a - z表示从a到z的字符),所以我们需要把它放在字符类的开头或者结尾,避免混淆。

深入“或”与预查机制

在PHP正则中,还有一种预查机制跟我们的“或”操作有一定关联。预查包括正向预查和反向预查。

(一)正向预查

正向预查的格式是(?=pattern),它表示在匹配某个模式之前要符合另一个模式。例如,我们想要匹配一个数字,但是这个数字的后面必须跟着字母。我们可以这样写:


$string3 = "1a2b3c";
$pattern2 = '/\d(?=\w)/';
if (preg_match_all($pattern2, $string3, $matches)) {
    var_dump($matches);
}

这里我们看到,虽然我们匹配的是数字,但是这个数字的匹配是以它后面跟着字母为条件的。这在某种程度上也是一种广义的“或”概念,因为我们是在数字和条件(后面是字母)之间建立了一种关联。

(二)反向预查

反向预查的格式是(?!pattern),它表示在匹配某个模式时,这个模式后面不能是另一个指定的模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值