我很好奇,如果你有一个字符串,你会如何检测分隔符?
我们知道php可以使用explode()分割字符串,这需要一个分隔符参数。
但是在将分隔符发送到爆炸函数之前检测分隔符的方法呢?
现在我只是将字符串输出给用户,然后输入分隔符。这很好 - 但我正在寻找模式识别的应用程序。
我应该在字符串中查找这种类型的模式识别的正则表达式吗?
编辑:我最初没有指定可能存在一组预期的分隔符。可能在CSV中使用的任何分隔符。所以从技术上讲,任何人都可以使用任何字符来分隔CSV文件,但更有可能使用以下字符之一:逗号,分号,竖线和空格。
编辑2:这是我为“确定的分隔符”提出的可行解决方案。
$get_images = "86236058.jpg 86236134.jpg 86236134.jpg";
//Detection of delimiter of image filenames.
$probable_delimiters = array(",", " ", "|", ";");
$delimiter_count_array = array();
foreach ($probable_delimiters as $probable_delimiter) {
$probable_delimiter_count = substr_count($get_images, $probable_delimiter);
$delimiter_count_array[$probable_delimiter] = $probable_delimiter_count;
}
$max_value = max($delimiter_count_array);
$determined_delimiter_array = array_keys($delimiter_count_array, max($delimiter_count_array));
while( $element = each( $determined_delimiter_array ) ){
$determined_delimiter_count = $element['key'];
$determined_delimiter = $element['value'];
}
$images = explode("{$determined_delimiter}", $get_images);
答案 0 :(得分:8)
确定您认为可能的分隔符(例如,
,;
和|
)以及每次搜索它们在字符串中出现的频率(substr_count
)。然后选择具有最多出现次数的那个作为分隔符并explode
。
即使这可能不是故障安全的,但在大多数情况下都应该有效;)
答案 1 :(得分:4)
我会说这有99.99%的情况:) 基本思想是,有效分隔符的数量应该逐行相同。 此脚本计算所有行之间的分隔符计数差异。 较少的差异意味着更有可能是有效的分隔符。
将所有内容放在一起这个函数读取行并将其作为数组返回:
function readCSV($fileName)
{
//detect these delimeters
$delA = array(";", ",", "|", "\t");
$linesA = array();
$resultA = array();
$maxLines = 20; //maximum lines to parse for detection, this can be higher for more precision
$lines = count(file($fileName));
if ($lines < $maxLines) {//if lines are less than the given maximum
$maxLines = $lines;
}
//load lines
foreach ($delA as $key => $del) {
$rowNum = 0;
if (($handle = fopen($fileName, "r")) !== false) {
$linesA[$key] = array();
while ((($data = fgetcsv($handle, 1000, $del)) !== false) && ($rowNum < $maxLines)) {
$linesA[$key][] = count($data);
$rowNum++;
}
fclose($handle);
}
}
//count rows delimiter number discrepancy from each other
foreach ($delA as $key => $del) {
echo 'try for key=' . $key . ' delimeter=' . $del;
$discr = 0;
foreach ($linesA[$key] as $actNum) {
if ($actNum == 1) {
$resultA[$key] = 65535; //there is only one column with this delimeter in this line, so this is not our delimiter, set this discrepancy to high
break;
}
foreach ($linesA[$key] as $actNum2) {
$discr += abs($actNum - $actNum2);
}
//if its the real delimeter this result should the nearest to 0
//because in the ideal (errorless) case all lines have same column number
$resultA[$key] = $discr;
}
}
var_dump($resultA);
//select the discrepancy nearest to 0, this would be our delimiter
$delRes = 65535;
foreach ($resultA as $key => $res) {
if ($res < $delRes) {
$delRes = $res;
$delKey = $key;
}
}
$delimeter = $delA[$delKey];
echo '$delimeter=' . $delimeter;
//get rows
$row = 0;
$rowsA = array();
if (($handle = fopen($fileName, "r")) !== false) {
while (($data = fgetcsv($handle, 1000, $delimeter)) !== false) {
$rowsA[$row] = Array();
$num = count($data);
for ($c = 0; $c < $num; $c++) {
$rowsA[$row][] = trim($data[$c]);
}
$row++;
}
fclose($handle);
}
return $rowsA;
}
答案 2 :(得分:2)
我有同样的问题,我正在处理来自各种数据库的很多CSV,各种各样的人以各种方式提取到CSV,有时每次对同一数据集都有不同...简单地实现了这样的函数我的转换基类
protected function detectDelimiter() {
$handle = @fopen($this->CSVFile, "r");
if ($handle) {
$line=fgets($handle, 4096);
fclose($handle);
$test=explode(',', $line);
if (count($test)>1) return ',';
$test=explode(';', $line);
if (count($test)>1) return ';';
//.. and so on
}
//return default delimiter
return $this->delimiter;
}
答案 3 :(得分:-1)
我做了这样的事情:
$line = fgetcsv($handle, 1000, "|");
if (isset($line[1]))
{
echo "delimiter is: |";
$delimiter="|";
}
else
{
$line1 = fgetcsv($handle, 1000, ";");
if (isset($line1[1]))
{
echo "delimiter is: ;";
$delimiter=";";
}
else
{
echo "delimiter is: ,";
$delimiter=",";
}
}
这只是检查读取一行后是否有第二列。
答案 4 :(得分:-1)
我遇到了同样的问题。我的系统将从客户端接收CSV文件,但它可以使用“;”,“,”或“”作为分隔符,我会改进系统,以便客户端不必知道哪个是(他们从不这样做)。
我搜索并找到了这个库: https://github.com/parsecsv/parsecsv-for-php
非常好且易于使用。