omg*_*tch 6 php csv excel parsing line-breaks
我正在尝试使用PHP解析一组CSV数据,但存在一个主要问题.其中一个字段是长描述字段,其本身包含机箱内的换行符.
我的主要问题是编写一段可以逐行拆分数据的代码,但也可以识别不应该使用数据中的换行符.此字段中的换行符未正确转义,因此很难与合法的换行符区分开来.
我试图想出一个能够正确处理它的正则表达式,但到目前为止还没有运气.有任何想法吗?
CSV格式:
"####","text data here", "text data \n with linebreaks \n here"\n
"####","more text data", "more data \n with \n linebreaks \n here"\n
Run Code Online (Sandbox Code Playgroud)
Ste*_*hen 10
根据aleske,PHP的fgetcsv函数文档中的一位评论者:
PHP的CSV处理是非标准的,与RFC4180相矛盾,因此fgetcsv()无法正确处理[包含换行符]的文件......
他提供了以下功能来解决这个限制:
function csvstring_to_array(&$string, $CSV_SEPARATOR = ';', $CSV_ENCLOSURE = '"', $CSV_LINEBREAK = "\n") {
$o = array();
$cnt = strlen($string);
$esc = false;
$escesc = false;
$num = 0;
$i = 0;
while ($i < $cnt) {
$s = $string[$i];
if ($s == $CSV_LINEBREAK) {
if ($esc) {
$o[$num] .= $s;
} else {
$i++;
break;
}
} elseif ($s == $CSV_SEPARATOR) {
if ($esc) {
$o[$num] .= $s;
} else {
$num++;
$esc = false;
$escesc = false;
}
} elseif ($s == $CSV_ENCLOSURE) {
if ($escesc) {
$o[$num] .= $CSV_ENCLOSURE;
$escesc = false;
}
if ($esc) {
$esc = false;
$escesc = true;
} else {
$esc = true;
$escesc = false;
}
} else {
if ($escesc) {
$o[$num] .= $CSV_ENCLOSURE;
$escesc = false;
}
$o[$num] .= $s;
}
$i++;
}
// $string = substr($string, $i);
return $o;
}
Run Code Online (Sandbox Code Playgroud)
看起来它会成功.
我发现在将 CSV 转换为 unix 格式后,您可以使用普通的 CSV 解析器。
这是一个对我有用的函数。
function dos2unix($s) {
$s = str_replace("\r\n", "\n", $s);
$s = str_replace("\r", "\n", $s);
$s = preg_replace("/\n{2,}/", "\n\n", $s);
return $s;
}
Run Code Online (Sandbox Code Playgroud)
和一个解析函数
function csvstring_to_array($string, $separatorChar = ',', $enclosureChar = '"', $newlineChar = PHP_EOL) {
// @author: Klemen Nagode
$string = dos2unix($string);
$array = array();
$size = strlen($string);
$columnIndex = 0;
$rowIndex = 0;
$fieldValue="";
$isEnclosured = false;
for($i=0; $i<$size;$i++) {
$char = $string{$i};
$addChar = "";
if($isEnclosured) {
if($char==$enclosureChar) {
if($i+1<$size && $string{$i+1}==$enclosureChar){
// escaped char
$addChar=$char;
$i++; // dont check next char
}else{
$isEnclosured = false;
}
}else {
$addChar=$char;
}
}else {
if($char==$enclosureChar) {
$isEnclosured = true;
}else {
if($char==$separatorChar) {
$array[$rowIndex][$columnIndex] = $fieldValue;
$fieldValue="";
$columnIndex++;
}elseif($char==$newlineChar) {
echo $char;
$array[$rowIndex][$columnIndex] = $fieldValue;
$fieldValue="";
$columnIndex=0;
$rowIndex++;
}else {
$addChar=$char;
}
}
}
if($addChar!=""){
$fieldValue.=$addChar;
}
}
if($fieldValue) { // save last field
$array[$rowIndex][$columnIndex] = $fieldValue;
}
return $array;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
11564 次 |
最近记录: |