2011-02-25 75 views
1

我使用file()读取数据,并遍历每一行。需要能够将字符串拆分为“列”数组。问题是列甚至不是宽度(60个字符,40个字符等)。看起来像所有的功能这样做,期望列是固定的大小。将字符串拆分为数组(不等列长度)

这将在一个很大的数据文件上执行,因此需要最佳的性能。

数据示例。

XXXXXXXXXXXXXXXXXXXXXXXXXX         XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXX             XXX XXX     X   XXX 
XXXXXXXXXXXXXXX            XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXXXXXXXXXXXXXXXXXXX         XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXX             XXX XXX     X   XXX 
XXXXXXXXXXXXXXX            XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXXXXXXXXXXXXXXXXXXX         XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXX             XXX XXX     X   XXX 
XXXXXXXXXXXXXXX            XXXXXXXXXXXXX   XX  XXXXXX 
+0

所以没有标准的分隔符?列宽?字符?这个输出的重点是什么?人类的解释?同时给我们举一个例子*这个* data * – Jakub 2011-02-25 16:44:23

+0

例子添加。没有标准分隔符。是每行都有标准列,但每列与每行不同。 – 2011-02-25 16:49:43

+0

'X'代表什么? – RobertPitt 2011-02-25 17:36:21

回答

1

的简单方法是使用SUBSTR分裂列:

foreach (file($fn) as $i=>$line) { 
    $rows[$i] = array(substr($line, 0, 60), substr($line, 60, 40), substr($line, 100, 30)); 
} 

但出乎共同智慧这将是更快地使用PCRE和正则表达式来分割字符串:

preg_match_all('/^(.{60})(.{40})(.{30})\K/m', file_get_contents($fn), $rows, PREG_SET_ORDER); 

这里的缺点是它的每一行都包含一个空的[0](将包含原始行),并且数据列从索引[1]开始。

0

您可以可靠地做到这一点的唯一方法是,如果文件中已经有一些分隔符。

explode()分割字符串的分隔符,所以如果你知道你的文件列标签分离的,可以 explode('\t',$string) 得到列阵列。

除此之外,没有可靠的方法我可以想到,这将让你拔出可变大小的列,而不必事先知道大小。

+0

不能使用爆炸。我知道每列的大小,每行的总是相同的,只是每列之间不同而已。 – 2011-02-25 16:46:52

+0

@LouisW爆炸换行符? – kjy112 2011-02-25 16:47:41

0

在您对我以前的答案发表评论后,看起来substr()就是您所需要的。

如果你知道每一列的宽度,每行只是这样做:

$rows = array(); 
foreach($lines as $line) 
{ 
    $columns = array(); 
    array_push($columns, substr($line, FirstColStart, FirstColEnd)); 
    array_push($columns, substr($line, SecondColStart, SecondColEnd)); 
    //more array pushing for each column 
    array_push($rows, $columns); 
} 
//Do something with your 'row' array of columns ($rows) 
-1

这是我想出了。我认为列宽并未提前知道。

<?php 

$data = 'XXXXXXXXXXXXXXXXXXXXXXXXXX         XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXX             XXX XXX     X   XXX 
XXXXXXXXXXXXXXX            XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXXXXXXXXXXXXXXXXXXX         XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXX             XXX XXX     X   XXX 
XXXXXXXXXXXXXXX            XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXXXXXXXXXXXXXXXXXXX         XXXXXXXXXXXXX   XX  XXXXXX 
XXXXXXXXX             XXX XXX     X   XXX 
XXXXXXXXXXXXXXX            XXXXXXXXXXXXX   XX  XXXXXX'; 

$dataLines = explode("\n", $data); 

// detect column breaks 
$numDataLines = count($dataLines); 
$colBreaks = array(); 
$c = 0; 
while (true) { 
    $rowEnds = 0; // count how many rows have terminated in the current col. 
    $notSet = 0; // a special case of $rowEnds, when the line no longer has  
       // chars. 
    // run down each column. if there are no X's, then it is a col break. 
    for ($r = 0; $r < $numDataLines; ++$r) { 
     if (!isset($dataLines[$r][$c])) { 
      ++$notSet; 
      ++$rowEnds; 
     } elseif ($dataLines[$r][$c] != 'X') { 
      ++$rowEnds; 
     } 
    } 
    // if no lines have chars left, end the while loop. this counts as a col 
    // break. 
    if ($notSet == $numDataLines) { 
     $colBreaks[] = $c; 
     break; 
    } 
    // if no X's were in the line, this is a col break. 
    if ($rowEnds == $numDataLines) { 
     $colBreaks[] = $c; 
    } 
    ++$c; // move on to the next col 
} 

// now that we have all the col breaks, we simply iterate over them and slice 
// out the needed sections from each line to create the columns. 
$dataCols = array(); 
$left = 0; 
foreach ($colBreaks as $cb) { 
    // skip empty cols 
    if ($left == $cb) { 
     $left = $cb + 1; 
     continue; 
    } 
    $colLen = $cb - $left; 
    $dataCol = array(); 
    echo "left: $left, len: $colLen, cb: $cb\n"; 
    foreach ($dataLines as $dl) { 
     $dataCol[] = substr($dl, $left, $colLen); 
    } 
    $dataCols[] = implode("\n", $dataCol); 
    $left += $colLen + 1; 
} 

// tada! 
print_r($dataCols);