$escape 参数完全不直观,但它并不存在问题。以下是 fgetcsv() 行为的分解。在示例中,我使用下划线 (_) 表示空格,使用方括号 ([]) 表示各个字段
- 如果每个字段中的前导空格直接出现在包含符之前,则将被剥离:___"foo" -> [foo]
- 每个字段只能有一个包含符,但它将与出现在结束包含符和下一个分隔符/换行符之间的任何数据连接起来,包括任何尾随空格:___"foo"_"bar"__ -> [foo_"bar"__]
- 如果字段没有以(前导空格 +)包含符开头,则整个字段将被解释为原始数据,即使包含符字符出现在字段内的其他位置:_foo"bar"_ -> [_foo"bar"_]
- 分隔符不能在包含符之外转义,它们必须在包含符中进行转义。分隔符不需要在包含符中转义:"foo,bar","baz,qux" -> [foo,bar][baz,qux]; foo\,bar -> [foo\][bar]; "foo\,bar" -> [foo\,bar]
- 单个包含符中的双重包含符将转换为单个包含符:"foobar" -> [foobar]; "foo""bar" -> [foo"bar]; """foo""" -> ["foo"]; ""foo"" -> [foo""](空包含符后面跟着原始数据)
- $escape 参数按预期工作,但与包含符不同的是,它不会被反转义。有必要在代码中的其他地方对数据进行反转义:"\"foo\"" -> [\"foo\"]; "foo\"bar" -> [foo\"bar"]
注意:以下数据(这是非常常见的问题)是无效的:“\”。它的结构等同于 “@ 或换句话说,一个开放的包含符,一些数据,但没有结束包含符。
以下函数可用于获得预期行为
<?php
function fgetcsv_unescape_enclosures_and_escapes($fh, $length = 0, $delimiter = ',', $enclosure = '"', $escape = '\\') {
$fields = fgetcsv($fh, $length, $delimiter, $enclosure, $escape);
if ($fields) {
$regex_enclosure = preg_quote($enclosure);
$regex_escape = preg_quote($escape);
$fields = preg_replace("/{$regex_escape}({$regex_enclosure}|{$regex_escape})/", '$1', $fields);
}
return $fields;
}
function fgetcsv_unescape_all($fh, $length = 0, $delimiter = ',', $enclosure = '"', $escape = '\\') {
$fields = fgetcsv($fh, $length, $delimiter, $enclosure, $escape);
if ($fields) {
$regex_escape = preg_quote($escape);
$fields = preg_replace("/{$regex_escape}(.)/s", '$1', $fields);
}
return $fields;
}
function fgetcsv_unescape_all_strip_last($fh, $length = 0, $delimiter = ',', $enclosure = '"', $escape = '\\') {
$fields = fgetcsv($fh, $length, $delimiter, $enclosure, $escape);
if ($fields) {
$regex_escape = preg_quote($escape);
$fields = preg_replace("/{$regex_escape}(.?)/s", '$1', $fields);
}
return $fields;
}
?>
注意:理想情况下,括号外不应该有任何未转义的转义字符;字段应该被包含并转义。如果有,它们可能会被移除,具体取决于所使用的函数。