我需要检测csv文件中的哪种行结尾:
\n
(UNIX默认值)\r
(Mac Excel)\r\n
(Windows)获取除界,封闭和放大转义字符,我使用SplFileObject::getCsvControl - 对于结束字符的行来说会很棒。
打开文件
答案 0 :(得分:2)
我没有尝试过这个,但我认为这是一个有趣的问题所以这是我对可能的解决方案的抨击:
// first, have PHP auto-detect the line endings, like @AbraCadaver suggested:
ini_set("auto_detect_line_endings", true);
// now open the file and read a single line from it
$file = fopen('/path/to/file.csv', 'r');
fgets($file);
// fgets() moves the pointer, so get the current position
$position = ftell($file);
// now get a couple bytes (here: 10) from around that position
fseek($file, $position - 5);
$data = fread($file, 10);
// we no longer need the file
fclose($file);
// now find out how many of each type EOL there are in those 10 bytes
// expected result is that two of these will be 0 and one will be 1
$eols = array(
"\r\n" => substr_count($data, "\r\n"),
"\r" => substr_count($data, "\r"),
"\n" => substr_count($data, "\n"),
);
// sort the EOL count in reverse order, so that the EOL with the highest
// count (expected: 1) will be the first item
arsort($eols);
// get the first item's key
$eol = key($eols);
// $eol will now be "\r\n", "\r" or "\n"
可能有更好的方法,请注意我在这里对您的CSV文件做了一些假设:
如果您不能指望这些条件,则必须添加一些验证步骤,例如检查fgets()
的结果是否实际上是一个包含多个字符的字符串。如果行可能短于5个字节,您可能还必须考虑到结束的行可能为\r\n
这一事实,但通过寻找原始字节,我们碰巧最终得到了像"abcde\r\nfg\r"
这样的字符串,我们错过了第二个\n
,你会得到错误的结果。
但是如果你能确定CSV文件的结构,这可能是一个(肮脏的,我会承认)朝着正确方向迈出的一步。
答案 1 :(得分:0)
这是一个有趣的问题 - 没有人能够在这里为您提供完整的解决方案。显而易见的方法是:
1)继续读取文件,直到第一次出现\ r或\ n。在前者的情况下,再读一个字符以检查它是否后跟\ n。
这听起来很简单 - 但您需要实施报价处理以确定EOL是否嵌入在引用的数据字段中 - 并且您不知道如何引用数据。除了检测开始和结束报价之外,您还需要能够确定引用字符是否被转义 - 并且至少有两种不同的方式来转义引号字符。
2)分析文件中字符的频率。如果你可以忽略空格,alhpa字符和数字,那么最常用的余数应该是CSV元字符。但是那些不能用于非常短的文件的人。
3)在文件中创建数据字符串的表示,并查找记录模式,例如如果你发现数字,空间,alpha,空间,数字,标点符号,数字,spache,alpha,标点符号,alpha,空格,数字,标点符号,数字,空格,alpha,空格,数字,标点符号那么你可能会认为字段分隔符是一个空格,记录由标点符号分隔,标点符号也可以显示为嵌入字符。
但这需要一些非常复杂的代码。
如果是我,我只会询问提供文件的人是否提供文件格式的详细信息。或者,如果该信息不可用,则使用十六进制编辑器打开文件。
答案 2 :(得分:0)
我使用了@rickdenhaan解决方案,但发现arsort()和PHP版本存在问题。
如果eol为“ \ r \ n”,则$ eols数组为:
array(“ \ r \ n” => 1,“ \ r” => 1,“ \ n” => 1);
(因为除了找到1个“ \ r \ n”,还发现了1个“ \ r”和1个“ \ n”)
和 PHP 7 ,在arsort($ eols)之后,键顺序是相同的:
array(“ \ r \ n” => 1,“ \ r” => 1,“ \ n” => 1);
并在“ $ eol = key($ eols);”之后$ eol将为“ \ r \ n”
但是使用 PHP 5.6 ,在arsort($ eols)之后,键顺序为:
array(“ \ n” => 1,“ \ r” => 1,“ \ r \ n” => 1);
并在“ $ eol = key($ eols);”之后$ eol将为“ \ n”
我已经在“ $ eol = key($ eols);”之后解决了此检查:
if (($eols["\r\n"] == $eols["\r"]) AND ($eols["\r\n"] == $eols["\n"])) {
$line_separator = "\r\n";
}