You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP号码前缀匹配逻辑异常:匹配号码被写入CSV文件求助

解决前缀匹配CSV号码时的错误写入问题

我看了你的代码和需求,问题出在循环逻辑的顺序完全搞反了,而且重复读取文件的操作不仅低效,还直接导致了错误的结果。

问题根源分析

你当前的逻辑是:拿一个前缀,然后把file2从头到尾读一遍,只要当前号码不匹配这个前缀,就写入file3。这就意味着:

  • 一个号码哪怕匹配了某个前缀,只要它不匹配其他前缀,就会被反复写入file3。比如3246611864654匹配324661这个前缀,但当遍历到324662、324663这些前缀时,它都会因为不匹配而被写入file3,这就是匹配前缀的号码也出现在file3里的核心原因。
  • 每次循环前缀都重新打开file2,频繁的文件IO操作非常影响性能,完全没必要。

修正后的解决方案

正确的逻辑应该是:先把所有前缀收集到一个数组里,然后遍历file2的每个号码,检查这个号码是否匹配任意一个前缀,如果都不匹配,再写入file3。

下面是修正后的代码:

<?php
$file1 = "csv/file1.csv";
$file2 = "csv/file2.csv";
$file3 = "csv/file3.csv";

// 第一步:一次性收集所有有效的前缀到数组
$prefixes = [];
// 读取file1并跳过空行和换行符
$prefixLines = file($file1, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($prefixLines as $line) {
    // 提取每行开头的数字前缀
    if (preg_match('/^([0-9]+)/', $line, $matches)) {
        $prefixes[] = $matches[1];
    }
}

// 第二步:遍历file2的每个号码,检查是否匹配任意前缀
$outputFile = fopen($file3, "w");
if (!$outputFile) {
    die("无法打开输出文件 {$file3}");
}

$phoneLines = file($file2, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($phoneLines as $line) {
    $line = trim($line);
    if (empty($line)) continue;
    
    // 提取号码部分
    if (preg_match('/([0-9]+)/', $line, $matches)) {
        $phoneNumber = $matches[1];
        $isMatched = false;
        
        // 检查是否匹配任意一个前缀
        foreach ($prefixes as $prefix) {
            // PHP 8+ 用str_starts_with更高效,低版本可以换成preg_match("/^{$prefix}/", $phoneNumber)
            if (str_starts_with($phoneNumber, $prefix)) {
                echo "匹配前缀 {$prefix} 的号码:{$line}&nbsp;<br>";
                $isMatched = true;
                break; // 匹配到一个就停止检查,提升效率
            }
        }
        
        // 只有完全不匹配任何前缀的号码,才写入file3
        if (!$isMatched) {
            fputcsv($outputFile, [$line], ",", "'");
        }
    }
}

fclose($outputFile);
echo "处理完成!";
?>

额外优化建议

如果你的CSV文件格式规范(有表头、字段用逗号分隔),建议用fgetcsv读取文件,比正则提取更准确,能避免引号包裹内容等特殊情况的错误:

// 用fgetcsv读取file1的前缀(跳过表头)
$prefixFile = fopen($file1, "r");
if (!$prefixFile) die("无法打开 {$file1}");
fgetcsv($prefixFile); // 跳过表头行
while (($row = fgetcsv($prefixFile)) !== false) {
    $prefix = trim($row[0]);
    if (is_numeric($prefix)) {
        $prefixes[] = $prefix;
    }
}
fclose($prefixFile);

// 用fgetcsv读取file2的号码(跳过表头)
$phoneFile = fopen($file2, "r");
if (!$phoneFile) die("无法打开 {$file2}");
fgetcsv($phoneFile); // 跳过表头行
while (($row = fgetcsv($phoneFile)) !== false) {
    $phoneNumber = trim($row[0]);
    $isMatched = false;
    
    foreach ($prefixes as $prefix) {
        if (str_starts_with($phoneNumber, $prefix)) {
            echo "匹配前缀 {$prefix} 的号码:{$row[0]} {$row[1]}<br>";
            $isMatched = true;
            break;
        }
    }
    
    if (!$isMatched) {
        fputcsv($outputFile, $row, ",", "'"); // 直接写入原数组,保持CSV格式
    }
}
fclose($phoneFile);

另外,如果前缀数量较多,可以把前缀按长度从长到短排序,避免短前缀先匹配导致长前缀被忽略的问题(比如同时有34661和34661789时,先检查长前缀)。

内容的提问来源于stack exchange,提问作者Ervis Hysi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 03:28:17