0

我试图在 preg_match 的帮助下在 PHP 中搜索一些模式。搜索模式是这样的(但这是错误的):

    /[\d\s*-\s*\d\s*(usd|eur)]{1}/i

\d  starts with integer,
\s*  there can be any number of whitespaces,
- there must be exactly one minus sign
\s* there can be any number of whitespaces,
\d then must be integer
\s* there can be any number of whitespaces,
(usd|eur) any of the following words must be present but one
[\d\s*-\s*\d\s*(usd|eur)]{1} - in string there should be exactly one occurence

上面的模式不起作用,我做错了什么?供测试用:

<?php
    $pattern = '/[\d\s*-\s*\d\s*(usd|eur)]{1}/i';
    $query = '100-120 100-120';

    echo $pattern.'<br/>';
    echo $query.'<br/>';

    if(preg_match($pattern, $query))
        echo 'OK';
    else
        echo 'not OK!';
?>

注意: 我试图提取这样的数据:

The price of item is 100 - 120 usd in our market
4

2 回答 2

2

[...]是一个字符类。它的意思是“匹配这些字符中的任何一个”。[abc]将匹配 a、bc。它与字符串“abc”不匹配。

此外:

{1}意思是“匹配前面的表达式一次”。但是,匹配一次是默认设置。无需明确告诉它匹配一次。

\d匹配单个数字。根据您的示例,您想要\d+- 匹配一个至少由一位数字组成的数字。

这是您的模式应该是这样的:

/\d+\s*-\s*\d+\s*(usd|eur)/i
于 2013-04-09T06:54:25.900 回答
1

正则表达式是检查和修改文本的强大工具。正则表达式本身,具有几乎类似于迷你编程语言的通用模式符号,允许您描述和解析文本。它们使您能够在字符串中搜索模式,灵活准确地提取匹配项。但是,您应该注意,由于正则表达式更强大,它们也比更基本的字符串函数慢。如果您有特殊需要,您应该只使用正则表达式。

本教程简要概述了基本的正则表达式语法,然后考虑 PHP 提供的用于处理正则表达式的函数。

The Basics
Matching Patterns
Replacing Patterns
Array Processing 

PHP 支持两种不同类型的正则表达式:POSIX 扩展和 Perl 兼容正则表达式 (PCRE)。PCRE 函数比 POSIX 函数更强大,也更快,所以我们将专注于它们。

基础

在正则表达式中,大多数字符只匹配它们自己。例如,如果您在字符串“约翰踢足球”中搜索正则表达式“foo”,您会得到匹配项,因为“foo”出现在该字符串中。有些字符在正则表达式中有特殊含义。例如,美元符号 ($) 用于匹配以给定模式结尾的字符串。同样,正则表达式开头的插入符号 (^) 字符表示它必须匹配字符串的开头。匹配自己的字符称为文字。具有特殊含义的字符称为元字符。

点 (.) 元字符匹配除换行符 () 之外的任何单个字符。因此,模式 ht 匹配 hat、hothit、hut、h7t 等。竖线 (|) 元字符用于正则表达式中的替代项。它的行为很像逻辑 OR 运算符,如果你想构造一个匹配多个字符集的模式,你应该使用它。例如,模式 Utah|Idaho|Nevada 匹配包含“Utah”或“Idaho”或“Nevada”的字符串。括号为我们提供了一种对序列进行分组的方法。例如,(Nant|b)ucket 匹配“Nantucket”或“bucket”。使用括号将字符组合在一起以进行交替称为分组。

如果要匹配模式中的文字元字符,则必须使用反斜杠对其进行转义。

要在模式中指定一组可接受的字符,您可以自己构建字符类或使用预定义的字符类。字符类允许您将一堆字符表示为正则表达式中的单个项目。您可以通过将可接受的字符括在方括号中来构建自己的字符类。一个字符类匹配该类中的任何一个字符。例如,字符类 [abc] 匹配 a、b 或 c。要定义字符范围,只需输入第一个和最后一个字符,用连字符分隔。例如,要匹配所有字母数字字符:[a-zA-Z0-9]。您还可以创建一个否定字符类,它匹配任何不在该类中的字符。要创建否定字符类,请以 ^: [^0-9] 开始字符类。

元字符 +、*、? 和 {} 影响模式应匹配的次数。+ 表示“匹配一个或多个前面的表达式”,* 表示“匹配零个或多个前面的表达式”,以及?表示“匹配零个或前面的表达式之一”。花括号 {} 可以不同地使用。对于单个整数,{n} 表示“匹配前一个表达式的 n 次出现”,一个整数和一个逗号,{n,} 表示“匹配前一个表达式的 n 次或多次出现”,并且两个逗号分隔integers {n,m} 表示“如果前一个字符出现至少 n 次,但不超过 m 次,则匹配前一个字符”。

现在,看看这些例子:

Regular Expression  Will match...
foo     The string "foo"
^foo    "foo" at the start of a string
foo$    "foo" at the end of a string
^foo$   "foo" when it is alone on a string
[abc]   a, b, or c
[a-z]   Any lowercase letter
[^A-Z]  Any character that is not a uppercase letter
(gif|jpg)   Matches either "gif" or "jpeg"
[a-z]+  One or more lowercase letters
[0-9\.\-]   Аny number, dot, or minus sign
^[a-zA-Z0-9_]{1,}$  Any word of at least one letter, number or _
([wx])([yz])    wy, wz, xy, or xz
[^A-Za-z0-9]    Any symbol (not a number or a letter)
([A-Z]{3}|[0-9]{4})     Matches three letters or four numbers

Perl 兼容的正则表达式模拟模式的 Perl 语法,这意味着每个模式必须包含在一对分隔符中。通常使用斜杠 (/) 字符。例如,/模式/。

PCRE 函数可以分为几类:匹配、替换、拆分和过滤。

匹配模式

preg_match() 函数对字符串执行 Perl 样式的模式匹配。preg_match() 接受两个基本参数和三个可选参数。这些参数依次是正则表达式字符串、源字符串、存储匹配的数组变量、标志参数和可用于指定开始搜索的备用位置的偏移参数: preg_match ( pattern,主题 [, 匹配 [, 标志 [, 偏移量]]])

如果找到匹配项,preg_match() 函数返回 1,否则返回 0。让我们搜索字符串“Hello World!” 对于字母“ll”:

<?php
if (preg_match("/ell/", "Hello World!", $matches)) {
  echo "Match was found <br />";
  echo $matches[0];
}
?>

字母“ll”存在于“Hello”中,因此 preg_match() 返回 1 并且 $matches 变量的第一个元素填充了与模式匹配的字符串。下一个示例中的正则表达式正在查找字母“ell”,但会使用以下字符查找它们:

<?php
if (preg_match("/ll.*/", "The History of Halloween", $matches)) {
  echo "Match was found <br />";
  echo $matches[0];
}
?>

现在让我们考虑更复杂的例子。正则表达式最流行的用途是验证。下面的示例检查密码是否为“强”,即密码必须至少为 8 个字符,并且必须至少包含一个小写字母、一个大写字母和一个数字:

<?php
$password = "Fyfjk34sdfjfsjq7";

if (preg_match("/^.*(?=.{8,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$/", $password)) {
    echo "Your passwords is strong.";
} else {
    echo "Your password is weak.";
}
?>

^ 和 $ 在字符串的开头和结尾寻找一些东西。“.*”组合用于开头和结尾。如上所述,.(点)元字符表示任何字母数字字符,而 * 元字符表示“零或多个”。之间是括号中的分组。“?=”组合意味着“下一个文本必须是这样的”。此构造不捕获文本。在这个例子中,不是指定事物应该出现的顺序,而是说它必须出现,但我们并不担心顺序。

第一个分组是 (?=. {8,})。这将检查字符串中是否至少有 8 个字符。下一个分组 (?=. [0-9]) 表示“任何字母数字字符可以出现零次或多次,然后任何数字都可以出现”。所以这会检查字符串中是否至少有一个数字。但由于未捕获字符串,因此该数字可以出现在字符串中的任何位置。接下来的分组 (?=. [az]) 和 (?=. [AZ]) 在字符串中的任何位置相应地查找小写和大写字母。

最后,我们将考虑验证电子邮件地址的正则表达式:

<?php
$email = firstname.lastname@aaa.bbb.com;
$regexp = "/^[^0-9][A-z0-9_]+([.][A-z0-9_]+)*[@][A-z0-9_]+([.][A-z0-9_]+)*[.][A-z]{2,4}$/";

if (preg_match($regexp, $email)) {
    echo "Email address is valid.";
} else {
    echo "Email address is <u>not</u> valid.";
}
?>

此正则表达式检查开头的数字,并检查电子邮件地址中的用户名和域名中的多个句点。让我们尝试自己研究这个正则表达式。

出于速度原因,preg_match() 函数仅匹配它在字符串中找到的第一个模式。这意味着可以非常快速地检查字符串中是否存在模式。另一个函数 preg_match_all() 在模式允许的范围内将模式与字符串匹配多次,并返回匹配的次数。

替换模式

在上面的示例中,我们在字符串中搜索了模式,而搜索字符串保持不变。preg_replace() 函数查找与模式匹配的子字符串,然后用新文本替换它们。preg_replace() 接受三个基本参数和一个附加参数。这些参数依次是正则表达式、用于替换找到的模式的文本、要修改的字符串以及最后一个可选参数,它指定将替换多少匹配项。preg_replace(模式,替换,主题[,限制])

如果找到匹配项,则该函数返回更改后的字符串,否则返回原始字符串的未更改副本。在以下示例中,我们搜索版权短语并将年份替换为当前。

<?php
echo preg_replace("/([Cc]opyright) 200(3|4|5|6)/", "$1 2007", "Copyright 2005");
?>

在上面的示例中,我们在替换字符串中使用了反向引用。反向引用使您可以在替换字符串中使用匹配模式的一部分。要使用此功能,您应该使用括号来包装您可能想要使用的正则表达式的任何元素。您可以使用美元符号 ($) 和子模式的编号来引用子模式匹配的文本。例如,如果您使用子模式,则 $0 设置为整个匹配,然后将 $1、$2 等设置为每个子模式的单个匹配。

在以下示例中,我们将日期格式从“yyyy-mm-dd”更改为“mm/dd/yyy”:

<?php
echo preg_replace("/(\d+)-(\d+)-(\d+)/", "$2/$3/$1", "2007-01-25");
?>

我们还可以传递一个字符串数组作为主题来对所有字符串进行替换。要通过一次调用 preg_replace() 对同一字符串或字符串数​​组执行多次替换,我们应该传递模式和替换数组。看看这个例子:

<?php
$search = array ( "/(\w{6}\s\(w{2})\s(\w+)/e",
                  "/(\d{4})-(\d{2})-(\d{2})\s(\d{2}:\d{2}:\d{2})/");

$replace = array ('"$1 ".strtoupper("$2")',
                  "$3/$2/$1 $4");

$string = "Posted by John | 2007-02-15 02:43:41";     

echo preg_replace($search, $replace, $string);?>

在上面的示例中,我们使用了另一个有趣的功能 - 您可以对 PHP 说,一旦发生替换,匹配文本应该作为 PHP 代码执行。由于我们在正则表达式的末尾附加了一个“e”,PHP 将执行它所做的替换。也就是说,它将使用 strtoupper(name) 并将其替换为 strtoupper() 函数的结果,即 NAME。

数组处理

PHP 的 preg_split() 函数使您能够根据比字符的文字序列更复杂的内容来拆分字符串。当需要用动态表达式而不是固定表达式分割字符串时,这个函数就派上用场了。基本思想与 preg_match_all() 相同,只是它不是返回主题字符串的匹配片段,而是返回一个与指定模式不匹配的片段数组。以下示例使用正则表达式将字符串拆分为任意数量的逗号或空格字符:

<?php
$keywords = preg_split("/[\s,]+/", "php, regular expressions");
print_r( $keywords );
?>

另一个有用的 PHP 函数是 preg_grep() 函数,它返回与给定模式匹配的数组元素。此函数遍历输入数组,根据提供的模式测试所有元素。如果找到匹配项,则匹配元素作为包含所有匹配项的数组的一部分返回。以下示例搜索一个数组和所有以字母 AJ 开头的名称:

<?php
$names = array('Andrew','John','Peter','Nastin','Bill');
$output = preg_grep('/^[a-m]/i', $names);
print_r( $output );
?>
于 2013-04-09T07:22:05.607 回答