将文件名与通配符匹配时,正则表达式无法按预期工作

regex not working as expected when matching file names with wildcards

我正在编写一个 PHP 函数,它接受一个文件名数组,并在文件名与用户输入的一组条件不匹配时从该数组中删除文件名。该函数遍历数组并将每个值与正则表达式进行比较。正则表达式是通过插入来自用户输入的变量而形成的。如果用户没有指定变量,则在变量的位置插入正则表达式通配符。文件名都非常系统化,例如 2020-06-N-1.txt,所以我确切地知道文件名和用户输入的字符数。但是,当我 运行 代码时,与正则表达式不匹配的文件名仍在数组中。删除了一些不匹配的文件名,但留下了许多其他文件名。下面是我的 PHP 部分代码。感谢任何帮助。

function fileFilter() {
    global $fileArray, $fileFilterPattern;
    
    /* The loop starts at 2 and goes to count()-1 because the first 2 elements were removed 
earlier with unset */
    for ($j = 2; $j < count($fileArray) - 1; $j++) {
        if(!(preg_match($fileFilterPattern, $fileArray[$j]))) {
            unset($fileArray[$j]);
        }
    }
    return;
}

// If user does not provide a filter value, it gets converted into wildcard symbol
if ($month == '') {
    $month = '..';
}
if ($year == '') {
    $year = '....';
}
if ($section == '') {
    $section = '.';
}

$fileFilterPattern = "/{$year}-{$month}-{$section}-.\.txt/";

/* function only runs if user applied at least one filter */
if (!($month == '..' && $year == '....' && $section == '.')) {
    fileFilter();
}

下面我提供了一个示例,说明数组如何包含不匹配的元素。我使用 echo json_encode($fileArray);

获取我的输出数组

我的输入:
月份是 "" 年份是 ""
部分是 "L"

预期结果:
数组仅包含在节点 (YEAR-MONTH-**SECTION**-NUMBER.txt)

中具有 L 的文件

结果数组:

{"8":"2020-06-L-1.txt","9":"2020-06-L-2.txt","10":"2020-06-L-3.txt","11":"2020-06-L-4.txt","12":"2020-06-L-5.txt","15":"2020-06-N-3.txt","16":"2020-06-N-4.txt","17":"2020-06-N-5.txt","18":"2020-06-N-6.txt","19":"2020-06-O-1.txt","20":"2020-06-O-2.txt","21":"2020-06-O-3.txt","22":"2020-06-O-4.txt","23":"2020-06-S-1.txt","24":"2020-06-S-2.txt","25":"2020-06-S-3.txt"}

问题是在循环中使用 unset()。在下一次迭代中,索引不再与您使用 unset() 破坏数组之前的索引相同。有时,您可以使用 array_values() 来处理这个问题,但在这种情况下,只构建第二个仅包含您想要的值的数组会更简单。以下代码有效。我使用 array_values() 只是为了获取您提供的字符串并使索引恢复正常。

也就是说,因为“前 2 个元素已被删除 早些时候使用 unset" 你需要在数组上 运行 array_values() 在你到达这部分之前。

<?php

$str ='{"8":"2020-06-L-1.txt","9":"2020-06-L-2.txt","10":"2020-06-L-3.txt","11":"2020-06-L-4.txt","12":"2020-06-L-5.txt","15":"2020-06-N-3.txt","16":"2020-06-N-4.txt","17":"2020-06-N-5.txt","18":"2020-06-N-6.txt","19":"2020-06-O-1.txt","20":"2020-06-O-2.txt","21":"2020-06-O-3.txt","22":"2020-06-O-4.txt","23":"2020-06-S-1.txt","24":"2020-06-S-2.txt","25":"2020-06-S-3.txt"}';

$fileArray = json_decode($str, true);
$fileArray = array_values($fileArray);

echo '<p>fileArray: ';
var_dump($fileArray);
echo '</p>';

function fileFilter() {
    global $fileArray, $fileFilterPattern;
    $filteredArray = [];

    for ($j = 0; $j < count($fileArray); $j++) {
        if(preg_match($fileFilterPattern, $fileArray[$j]) === 1) {
            //unset($fileArray[$j]);
            array_push($filteredArray, $fileArray[$j]);
        }
    }
    echo '<p>filteredArray: ';
    var_dump($filteredArray);
    echo '</p>';
    //return;
}

$month =='';
$year = '';
// If user does not provide a filter value, it gets converted into wildcard symbol
if ($month == '') {
    $month = '..';
}
if ($year == '') {
    $year = '....';
}
if ($section == '') {
    $section = '.';
}

$section = 'L';

$fileFilterPattern = "#{$year}-{$month}-{$section}-.\.txt#";

echo '<p>fileFilterPattern: ';
var_dump($fileFilterPattern);
echo '</p>';

/* function only runs if user applied at least one filter */
if (!($month == '..' && $year == '....' && $section == '.')) {
    fileFilter();
}
?>

主要问题是每次 unsetcount 都会减少,因此您应该定义一次计数。假设 -1$j = 2 对您的场景是正确的:

$count = count($fileArray) - 1;

for ($j = 2; $j < $count; $j++) {
    if(!(preg_match($fileFilterPattern, $fileArray[$j]))) {
        unset($fileArray[$j]);
    }
}

还有其他方法,您不必假设并跟踪密钥:

foreach($fileArray as $k => $v) {
    if(!preg_match($fileFilterPattern, $v)) {
        unset($fileArray[$k]);
    }
}

我会去掉你的 fileFilter 函数,改用这个方便的函数,它将 return 所有匹配模式的项目:

$fileArray = preg_grep($fileFilterPattern, $fileArray);