将文本文件解析为 4 列,第 3 列有时有值,有时没有(PHP)

Posted

技术标签:

【中文标题】将文本文件解析为 4 列,第 3 列有时有值,有时没有(PHP)【英文标题】:Parse a text file into 4 columns, with the 3rd column sometimes has value and sometimes not (PHP) 【发布时间】:2021-06-29 13:55:51 【问题描述】:

大家! 我正在寻求帮助,因为我陷入困境并且不知道......

我需要将一个文本文件解析为 4 列,其中第 3 列有时有值,有时没有。

我尝试了很多选项...例如,将 3,4 空格替换为“分隔符”,将空格替换为另一个特殊字符...但我无法理解如何管理当前行中的 3 或 4 列

我已附上文件的一部分。 谢谢各位!

           246/RD/2010    05.01.2010                   211/P 12.11.2010
           247/RD/2010    05.01.2010                   195/P 09.11.2010
           248/RD/2010    05.01.2010     13.10.2010 
           251/RD/2010    05.01.2010                   274/P 08.12.2010
          996 /RD/2015    19.01.2015                  1049/P/04.12.2015
          997 /RD/2015    19.01.2015                  1049/P/04.12.2015
          998 /RD/2015    19.01.2015                  1049/P/04.12.2015
          999 /RD/2015    19.01.2015                  1049/P/04.12.2015
          1000 /RD/2015   19.01.2015                  1049/P/04.12.2015
          1001 /RD/2015   19.01.2015                  1049/P/04.12.2015
          1002 /RD/2015   19.01.2015                  1049/P/04.12.2015
          1003 /RD/2015   19.01.2015                  1049/P/04.12.2015
          1004 /RD/2015   19.01.2015                  1049/P/04.12.2015
          31600 /RD/2015  10.06.2015                  1152/P/12.09.2016
          31601 /RD/2015  10.06.2015                   690/P/26.05.2016
          31605 /RD/2015  10.06.2015                  1148/P/12.09.2016
          31608 /RD/2015  10.06.2015                  1150/P/12.09.2016
         149130/RD/2010   13.10.2010                   870/P/12.09.2011
         149136/RD/2010   13.10.2010                  1106/P/09.11.2011
         149137/RD/2010   13.10.2010                  1107/P/10.11.2011
         149138/RD/2010   13.10.2010                   868/P/12.09.2011
         149139/RD/2010   13.10.2010                   870/P/12.09.2011
         148931/RD/2010   13.10.2010                  1050/P/24.10.2011
         148932/RD/2010   13.10.2010                  1080/P/03.11.2011
         148933/RD/2010   13.10.2010                   883/P/13.09.2011
         148934/RD/2010   13.10.2010     28.01.2011 
         148935/RD/2010   13.10.2010                  1106/P/09.11.2011
         147809/RD/2010   06.10.2010                   881/P/13.09.2011
         147810/RD/2010   06.10.2010     19.10.2011 
         147811/RD/2010   06.10.2010                  1049/P/24.10.2011

【问题讨论】:

算出每列的宽度和substr 的大小。然后您可以trim() 删除多余的字符。 如果我理解你的答案正确,你解释了如何获取行。获取行不是问题,简单的explode("\n")。我的问题是弄清楚第三列在哪里,第四列在哪里 【参考方案1】:

您的问题可以通过正则表达式解决。但这有点棘手。这是我的缩写。它不关心列之间有多少空间。它匹配列的特定模式以区分它们。

// reduced test-data for simplicity
$data = '           246/RD/2010    05.01.2010                   211/P 12.11.2010
                    247/RD/2010    05.01.2010                   195/P 09.11.2010
                    248/RD/2010    05.01.2010     13.10.2010 
                    251/RD/2010    05.01.2010                   274/P 08.12.2010';

// regular-expression with groups to get your needed columns 
$re = '/^\s*([0-9]+\s*[0-9A-Z\/]+)\s+([0-9]2\.[0-9]2\.[0-9]4)\s+([0-9]2\.[0-9]2\.[0-9]4)*(\s*$|([0-9A-Z\/]+\s*[0-9]2\.[0-9]2\.[0-9]4$))/m';

// match it
preg_match_all ($re, $data, $matches, PREG_SET_ORDER, 0);

// $matches is now an multidimensional array with an array for every line. 
// those line-arrays will contain columns 1 to 5 where 3 will 
// be your third column (sometimes empty) and 5 will be the last column.

// [
//   ['246/RD/2010', '05.01.2010', '',           '', '211/P 12.11.2010'],
//   ['247/RD/2010', '05.01.2010', '',           '', '195/P 09.11.2010'],
//   ['248/RD/201',  '05.01.2010', '13.10.2010', '', ''],
//   ['251/RD/2010', '05.01.2010', '',           '', '274/P 08.12.2010'],
// ]

【讨论】:

非常感谢!这部分简直令人叹为观止! ([0-9]2\.[0-9]2\.[0-9]4)*(\s*$|([0-9A-Z\/]+\s *[0-9]2\.[0-9]2\.[0-9]4$)) @AlexF 不客气。很高兴我能帮上忙。【参考方案2】:

它看起来像一个固定格式的文件,因此它期望每个字段位于每一行中的某个点。您可以使用substr() 提取行的每个部分,其中包含一个起点和该字段应包含的字符数。还可以在结果中使用trim() 删除任何多余的空格。

这只是对字段位置的粗略猜测,您需要检查每个字段的开始位置,您可以看到我从第一列中的日期得到0...

$file =
'           246/RD/2010    05.01.2010                   211/P 12.11.2010
           247/RD/2010    05.01.2010                   195/P 09.11.2010
           248/RD/2010    05.01.2010     13.10.2010
           251/RD/2010    05.01.2010                   274/P 08.12.2010
';

foreach ( explode(php_EOL, $file) as $line )    
    if ( !empty($line) )    
        $c1 = trim(substr($line, 0, 27));
        $c2 = trim(substr($line, 27, 14));
        $c3 = trim(substr($line, 41, 14));
        $c4 = trim(substr($line, 56) ?: '');
        echo $c1."###".$c2."###".$c3."###".$c4.PHP_EOL;
    

这给了...

246/RD/2010    0###5.01.2010######11/P 12.11.2010
247/RD/2010    0###5.01.2010######95/P 09.11.2010
248/RD/2010    0###5.01.2010###13.10.2010###
251/RD/2010    0###5.01.2010######74/P 08.12.2010

我在$c4 上使用了 ?: '',以防线条没有完全填充(尽可能全长)。

【讨论】:

【参考方案3】:

由于您的文件是固定宽度的文档,您可以使用substr 对其进行解析。在大多数情况下,更好的方法是使用空格as explained here 使用preg_split,但在您的情况下,最后一列也可以包含空格(例如211/P 12.11.2010

因此,最好的方法是计算字符数,并根据substr 创建列。然后,您可以像其他人建议的那样使用 trim 来删除多余的空格。

在代码中

$f = file_get_contents('file.txt');
$f = explode("\n", $f);

$cols = [
    [0,25],
    [25,13],
    [38,16],
    [54,18]
];

$result = [];
foreach ($f as $count => $line) 
    $result[$count] = [];
    foreach ($cols as $c) 
        $result[$count][] = trim(substr($line, $c[0], $c[1]));
    

var_dump($result);

这会给你类似的结果

array(30) 
  [0]=>
  array(4) 
    [0]=>
    string(11) "246/RD/2010"
    [1]=>
    string(10) "05.01.2010"
    [2]=>
    string(0) ""
    [3]=>
    string(16) "211/P 12.11.2010"
  
.
.
.
  [29]=>
  array(4) 
    [0]=>
    string(14) "147811/RD/2010"
    [1]=>
    string(10) "06.10.2010"
    [2]=>
    string(0) ""
    [3]=>
    string(17) "1049/P/24.10.2011"
  

【讨论】:

以上是关于将文本文件解析为 4 列,第 3 列有时有值,有时没有(PHP)的主要内容,如果未能解决你的问题,请参考以下文章

关于Linux下的文本文件格式转换问题。

Bigquery 加载列中包含“null”文本的 CSV 文件

替换第一列文本中的特定字符

如何从 SQL 中提取 JSON 值,其中列值有时为空

在 SELECT 中检查 3 列

使用 awk 或 perl 从 CSV 中提取特定列(解析)