fgetcsv返回字符串长度异常,正则匹配失效求解决
问题:fgetcsv读取CSV返回字符串长度异常,正则匹配失败
我正在开发一个简单脚本,用于从CSV文件读取URL并执行正则匹配,但正则模式始终匹配失败。仔细排查后发现异常:fgetcsv返回的字符串经var_dump()输出的长度完全不符合实际。
示例代码
$read = fopen("input.csv","r"); while($data = fgetcsv($read,null,",","\"","\\")){ var_dump($data[0]); echo mb_detect_encoding($data[0]); echo "\n"; }
输出结果
string(25) "/index.html" ASCII string(23) "/login.html" ASCII string(15) "/insta/" ASCII
CSV文件中的字符串与返回的内容一致,但显示的长度明显错误。这是什么原因?是否存在无法看见的隐形字符?或是特殊编码问题?该如何解决?
原因分析
问题出在**UTF-8 BOM(字节顺序标记)**上。你的CSV文件开头带有三个不可见的字节(EF BB BF),也就是UTF-8 BOM。虽然mb_detect_encoding检测结果显示为ASCII,但BOM字节会被算入字符串长度中:
- 第一个字符串
"/index.html"实际长度是22,但显示为25,多出来的3个字节就是BOM的长度; - 后续行没有BOM,长度相对正常,但第一行的隐形字符会直接导致正则匹配失败。
解决方案
1. 手动去除CSV文件的BOM
用文本编辑器(如Notepad++)打开CSV文件,选择「编码」→「UTF-8无BOM」,保存即可彻底解决问题。
2. 在PHP代码中处理BOM
可以在读取文件时跳过BOM,或者对读取到的字符串做清理:
方式一:读取时跳过BOM
$read = fopen("input.csv","r"); // 读取前3个字节判断是否是UTF-8 BOM $bom = fread($read, 3); if ($bom !== "\xEF\xBB\xBF") { // 不是BOM则把指针移回开头 fseek($read, 0); } while($data = fgetcsv($read,null,",","\"","\\")){ var_dump($data[0]); echo mb_detect_encoding($data[0]); echo "\n"; } fclose($read);
方式二:清理字符串中的BOM
$read = fopen("input.csv","r"); while($data = fgetcsv($read,null,",","\"","\\")){ // 去除字符串开头的BOM $url = preg_replace('/^\x{FEFF}/u', '', $data[0]); var_dump($url); echo mb_detect_encoding($url); echo "\n"; } fclose($read);
3. 使用file_get_contents配合str_getcsv(可选)
如果CSV文件不大,可以先读取整个文件并去除BOM,再解析:
$content = file_get_contents("input.csv"); // 去除BOM $content = preg_replace('/^\x{FEFF}/u', '', $content); $rows = str_getcsv($content, "\n"); foreach ($rows as $row) { $data = str_getcsv($row); var_dump($data[0]); }
内容的提问来源于stack exchange,提问作者Gedi Nixan
相关产品推荐
相关产品推荐

