fnmatch

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

fnmatch将文件名与模式匹配

说明

fnmatch(string $pattern, string $filename, int $flags = 0): bool

fnmatch() 检查传递的 filename 是否与给定的 shell 通配符 pattern 匹配。

参数

pattern

要匹配的 pattern。通常,pattern 将包含通配符,如 '?''*'

pattern 参数中使用的通配符
通配符 说明
? 问号将匹配任何单个字符。例如,模式 "file?.txt" 将匹配 "file1.txt""fileA.txt",但不会匹配 "file10.txt"
* 星号将匹配零个或多个字符。例如,模式 "foo*.xml" 将匹配 "foo.xml""foobar.xml"
[ ] 方括号用于创建 ASCII 码点范围或字符集。例如,模式 "index.php[45]" 将匹配 "index.php4""index.php5",但不会匹配 "index.phpt"。众所周知的范围是 [0-9][a-z][A-Z]。可以同时使用多个集合和范围,例如 [0-9a-zABC]
! 感叹号用于否定方括号内的字符。例如,"[!A-Z]*.html" 将匹配 "demo.html",但不会匹配 "Demo.html"
\ 反斜杠用于转义特殊字符。例如,"Name\?" 将匹配 "Name?",但不会匹配 "Names"

filename

要测试的字符串。此函数特别适用于文件名,但也可能用于常规字符串。

普通用户可能习惯使用 shell 模式,或者至少习惯于使用最简单的形式 '?''*' 通配符,因此使用 fnmatch() 而不是 preg_match() 用于前端搜索表达式输入可能对非编程用户更方便。

flags

flags 的值可以是以下任何标志的组合,使用 按位或 (|) 运算符 连接。

fnmatch() 的可能标志列表
标志 说明
FNM_NOESCAPE 禁用反斜杠转义。
FNM_PATHNAME 字符串中的斜杠仅匹配给定模式中的斜杠。
FNM_PERIOD 字符串中的前导句点必须与给定模式中的句点完全匹配。
FNM_CASEFOLD 不区分大小写匹配。属于 GNU 扩展的一部分。

返回值

如果匹配,则返回 true,否则返回 false

示例

示例 #1 检查颜色名称与 shell 通配符模式

<?php
if (fnmatch("*gr[ae]y", $color)) {
echo
"某种灰色...";
}
?>

备注

警告

目前,此函数在非 POSIX 兼容系统(除了 Windows)上不可用。

参见

  • glob() - 查找与模式匹配的路径名
  • preg_match() - 执行正则表达式匹配
  • sscanf() - 根据格式解析来自字符串的输入
  • printf() - 输出格式化的字符串
  • sprintf() - 返回格式化的字符串

添加说明

用户贡献说明 9 说明

me at rowanlewis dot com
13 年前
这是一个明确的解决方案,它支持负字符类和四个已记录的标志。

<?php

if (!function_exists('fnmatch')) {
define('FNM_PATHNAME', 1);
define('FNM_NOESCAPE', 2);
define('FNM_PERIOD', 4);
define('FNM_CASEFOLD', 16);

function
fnmatch($pattern, $string, $flags = 0) {
return
pcre_fnmatch($pattern, $string, $flags);
}
}

function
pcre_fnmatch($pattern, $string, $flags = 0) {
$modifiers = null;
$transforms = array(
'\*' => '.*',
'\?' => '.',
'\[\!' => '[^',
'\[' => '[',
'\]' => ']',
'\.' => '\.',
'\\' => '\\\\'
);

// Forward slash in string must be in pattern:
if ($flags & FNM_PATHNAME) {
$transforms['\*'] = '[^/]*';
}

// Back slash should not be escaped:
if ($flags & FNM_NOESCAPE) {
unset(
$transforms['\\']);
}

// Perform case insensitive match:
if ($flags & FNM_CASEFOLD) {
$modifiers .= 'i';
}

// Period at start must be the same as pattern:
if ($flags & FNM_PERIOD) {
if (
strpos($string, '.') === 0 && strpos($pattern, '.') !== 0) return false;
}

$pattern = '#^'
. strtr(preg_quote($pattern, '#'), $transforms)
.
'$#'
. $modifiers;

return (boolean)
preg_match($pattern, $string);
}

?>

这可能需要进一步测试,但它似乎与本地 fnmatch 实现功能相同。
bernd dot ebert at gmx dot net
12 年前
pcre_fnmatch 函数中存在一个关于反斜杠的问题。如果未设置 FN_NOESCAPE,它们将被 preq_quote 掩盖,并被 strtr 额外掩盖 -> 像“*a(*”这样的东西最终将变成“#^.*a\\(.*$#”。注意双反斜杠实际上并没有正确掩盖“()”。

由于 preq_quote 始终匹配反斜杠,我认为使用 preg_quote 根本无法实现这一点。
Sinured
16 年前
补充我之前笔记的内容:我关于 FNM_* 常量的陈述是错误的。它们在符合 POSIX 的系统上可用(换句话说,如果定义了 fnmatch())。
jk at ricochetsolutions dot com
17 年前
soywiz 的函数似乎不适合我,但这个函数有效。

<?php
if(!function_exists('fnmatch')) {

function
fnmatch($pattern, $string) {
return
preg_match("#^".strtr(preg_quote($pattern, '#'), array('\*' => '.*', '\?' => '.'))."$#i", $string);
}
// end

} // end if
?>
Frederik Krautwald
17 年前
soywiz 的函数仍然似乎不起作用 - 至少在 Windows 上的 PHP 5.2.3 上不起作用 - 但 jk 的函数有效。
theboydanny at gmail dot com
16 年前
关于下面的 windows 兼容函数
我需要 fnmatch 用于一个必须在 Windows 上运行的应用程序,我在这里查看并测试了这两个函数。Jk 的函数对我有用,soywiz 的没有(在 WinXPSP2,PHP 5.2.3 上)。
它们之间的唯一区别是 addcslashes(soywiz)而不是 preg_quote(jk)。它们 _应该_ 都能工作,但出于某种原因,soywiz 的函数对我无效。所以 YMMV。
但是,为了使 JK 的 fnmatch() 与文档中的示例一起使用,你还要对 $pattern 中的 [ 和 ] 进行 strtr 处理。
<?php
$pattern
= strtr(preg_quote($pattern, '#'), array('\*' => '.*', '\?' => '.', '\[' => '[', '\]' => ']'));
?>
感谢各位提供的函数。
phlipping at yahoo dot com
21 年前
你也可以尝试这个函数,它是我在找到 fnmatch 之前写的。

function WildToReg($str)
{
$s = "";
for ($i = 0; $i < strlen($str); $i++)
{
$c = $str{$i};
if ($c =='?')
$s .= '.'; // 任何字符
else if ($c == '*')
$s .= '.*'; // 0 个或多个任何字符
else if ($c == '[' || $c == ']')
$s .= $c; // [] 中的一个字符
else
$s .= '\\' . $c;
}
$s = '^' . $s . '$';

// 修剪冗余的 ^ 或 $
// 例如 ^.*\.txt$ 与 \.txt$ 匹配完全相同
if (substr($s,0,3) == "^.*")
$s = substr($s,3);
if (substr($s,-3,3) == ".*$")
$s = substr($s,0,-3);
return $s;
}

if (ereg(WildToReg("*.txt"), $fn))
print "$fn 是一个文本文件";
else
print "$fn 不是一个文本文件";
Sinured
17 年前
可能的标志(从 fnmatch.h 中删除)
...::...

FNM_PATHNAME
> $string 中的斜杠只匹配 $pattern 中的斜杠。

FNM_PERIOD
> $string 中的开头句点必须与 $pattern 中的句点完全匹配。

FNM_NOESCAPE
> 禁用反斜杠转义。

FNM_NOSYS
> 已过时。

FNM_FILE_NAME
> FNM_PATHNAME 的别名。

FNM_LEADING_DIR
> 来自 fnmatch.h:/* 忽略匹配后的“/...”。 */

FNM_CASEFOLD
> 不区分大小写的匹配。

由于它们出现在 file.c 中,但 PHP 中不可用,因此我们需要自己定义它们。
<?php
define
('FNM_PATHNAME', 1);
define('FNM_PERIOD', 4);
define('FNM_NOESCAPE', 2);
// GNU 扩展
define('FNM_FILE_NAME', FNM_PATHNAME);
define('FNM_LEADING_DIR', 8);
define('FNM_CASEFOLD', 16);
?>

除了 casefold 之外,我没有测试过任何这些功能,并且它对我有用。
bwilcock at gmail dot com
10 年前
fnmatch 不完全可靠。错误 14185 仍然存在,可能已修复也可能未修复。

在某些通配符情况下,fnmatch("*needle*", $haystack, match) 间歇性地返回 false

但是 stripos 或 preg 返回“找到”。
To Top