如何在PHP中检测字符串中的分隔符?
我很好奇,如果你有一个字符串,你将如何检测分隔符 我们知道php可以使用explode()拆分字符串,explode()需要一个分隔符参数 但是,在将分隔符发送到分解函数之前,如何检测分隔符呢 现在我只是将字符串输出给用户,用户输入分隔符。这很好,但我正在寻找一个模式识别的应用程序 我应该在字符串中寻找这种类型的模式识别的正则表达式吗 编辑:我最初未能指定可能存在预期的分隔符集。CSV中可能使用的任何分隔符。因此,从技术上讲,任何人都可以使用任何字符来分隔CSV文件,但更可能使用以下字符之一:逗号、分号、竖线和空格 编辑2:下面是我为“确定的分隔符”提出的可行解决方案如何在PHP中检测字符串中的分隔符?,php,string,delimiter,Php,String,Delimiter,我很好奇,如果你有一个字符串,你将如何检测分隔符 我们知道php可以使用explode()拆分字符串,explode()需要一个分隔符参数 但是,在将分隔符发送到分解函数之前,如何检测分隔符呢 现在我只是将字符串输出给用户,用户输入分隔符。这很好,但我正在寻找一个模式识别的应用程序 我应该在字符串中寻找这种类型的模式识别的正则表达式吗 编辑:我最初未能指定可能存在预期的分隔符集。CSV中可能使用的任何分隔符。因此,从技术上讲,任何人都可以使用任何字符来分隔CSV文件,但更可能使用以下字符之一:逗
确定您认为可能的分隔符(如<代码>、<代码>、<代码>、和<代码> <代码>),并针对每个搜索在字符串中出现的次数(<代码>子目录计数< /代码>)。然后选择出现次数最多的一个作为分隔符,然后分解
尽管这可能不是故障保护,但在大多数情况下它都应该工作;) 我也有同样的问题,我正在处理来自不同数据库的大量CSV,不同的人以不同的方式提取到CSV,有时同一数据集的每次提取都不同。。。在我的convert基类中实现了这样的函数
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;
}
我做了这样的东西:
$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=",";
}
}
这只是检查在读取一行后是否有第二列。我想说,这在99.99%的情况下有效:) 其基本思想是,有效分隔符的数量应逐行相同。 此脚本计算所有行之间的分隔符计数差异。 越小的差异意味着越可能是有效的分隔符
$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);
将其放在一起此函数读取行并将其作为数组返回:
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;
}
函数readCSV($fileName)
{
//检测这些纤度计
$delA=数组(“;”、“,”、“|”、“\t”);
$linesA=array();
$resultA=array();
$maxLines=20;//要分析以进行检测的最大行数,可以更高以获得更高的精度
$lines=计数(文件($fileName));
如果($lines<$maxLines){//如果行小于给定的最大值
$maxLines=$lines;
}
//载重线
foreach($delA作为$key=>$del){
$rowNum=0;
if($handle=fopen($fileName,“r”)!==false){
$linesA[$key]=array();
而(($data=fgetcsv($handle,1000,$del))!==false)和($rowNum<$maxLines)){
$linesA[$key][]=计数($data);
$rowNum++;
}
fclose($handle);
}
}
//计数行分隔符编号彼此不符
foreach($delA作为$key=>$del){
回显'try for key='。$key.'delimeter='。$del;
$discr=0;
foreach($linesA[$key]作为$actNum){
如果($actNum==1){
$resultA[$key]=65535;//此行中只有一列具有此delimeter,因此这不是我们的分隔符,请将此差异设置为高
打破
}
foreach($linesA[$key]作为$actNum2){
$discr+=abs($actNum-$actNum2);
}
//如果是真实的delimeter,则该结果应最接近于0
//因为在理想(无错误)情况下,所有行都有相同的列号
$resultA[$key]=$discr;
}
}
var_dump($resultA);
//选择最接近0的差异,这将是我们的分隔符
$delRes=65535;
foreach($resultA as$key=>$res){
如果($res<$delRes){
$delRes=$res;
$delKey=$key;
}
}
$delimeter=$delA[$delKey];
回声“$delimeter=”。$delimeter;
//吵架
$row=0;
$rowsA=array();
if($handle=fopen($fileName,“r”)!==false){
while(($data=fgetcsv($handle,1000,$delimeter))!==false){
$rowsA[$row]=数组();
$num=计数($data);
对于($c=0;$c<$num;$c++){
$rowsA[$row][]=trim($data[$c]);
}
$row++;
}
fclose($handle);
}
返回$rowsA;
}
我也有同样的问题。我的系统将从客户端接收CSV文件,但它可以使用“;”、“、”或“”作为分隔符,并且我可以改进系统,这样客户端就不必知道哪个是(他们永远不会知道) 我搜索并找到了此库:
非常好且易于使用。分隔符是什么样子的?我对让用户指定分隔符的逻辑感到困惑。这样做的目的是什么?为什么不直接使用任何一个常用的定界符并完成它呢?@Alex如果任何东西都可以是定界符,那么你所要求的听起来很不现实。模式匹配以检测分隔符是一项非常重要的任务,您按照此规范提出的任何内容都将是O(n^c)。其中n是所有可能分隔符的集合,c是字符串长度。丑陋…好吧,您可以构建一个启发式系统,尝试从可能的分隔符列表中识别分隔符(
,;/|
)。根据需要,您可以对字符在文件中出现的次数进行计数分析(毕竟,我认为分隔符在每行中至少会出现几次)…这注定会经常失败。如果我的内容中包含大量的||||||代码>?如果是为了实验目的,它可以是一个开始。否则,这样的构造将导致系统崩溃。一种选择是,如果计数超过一个,或者它们很接近,则逐行遍历文件并计数出现的次数。数字最稳定的一个(不同