【问题标题】:How to parse fixed width column text in php?如何在php中解析固定宽度的列文本?
【发布时间】:2012-06-10 04:43:49
【问题描述】:

如何在php中解析显示下面的文本并输出到hmtl中?

我需要的是提示如何处理分隔列的空间。空格数不固定,所以我不能使用explode(" ",$string); 而且我不确定下面输出的结构是否真的有固定宽度的列。我想让解析函数通用。

输出来自db2 list applications

Auth Id  Application    Appl.      Application Id                                                 DB       # of
         Name           Handle                                                                    Name    Agents
-------- -------------- ---------- -------------------------------------------------------------- -------- -----
DB2INST1 db2jcc_applica 11446      10.0.0.209.51406.120606004531                                  WEI      1    
DB2INST1 db2jcc_applica 11448      10.0.0.209.51407.120606004536                                  WEI      1    
DB2INST1 db2jcc_applica 13762      10.0.0.206.57473.120606024909                                  DOM_BUGS 1    
ADMIN    db2jcc_applica 15220      10.0.0.210.52248.120606045402                                  RATIONAL 1    
DB2INST1 php-fpm: pool  16546      127.0.0.2.35530.120606065726                                   KON      1    
DB2INST1 db2jcc_applica 16547      10.0.0.202.52042.120606065813                                  KON      1 

【问题讨论】:

    标签: php parsing


    【解决方案1】:

    首先有sscanf

    $vars = sscanf($string, '%s %s %d %s');
    

    它针对空格分隔值进行了优化,您已经可以指定变量类型(%s = string;%d = integer)(;甚至命名变量,但示例中没有演示)。

    例子/Demo:

    $lines = explode("\r\n", $input);
    
    foreach($lines as &$line)
    {
        $line = sscanf($line, '%s %s %d %s');
    }
    
    var_dump($lines);
    

    输出:

    array(6) {
      [0]=>
      array(4) {
        [0]=>
        string(8) "DB2INST1"
        [1]=>
        string(14) "db2jcc_applica"
        [2]=>
        int(11446)
        [3]=>
        string(29) "10.0.0.209.51406.120606004531"
      }
      [1]=>
      array(4) {
        [0]=>
        string(8) "DB2INST1"
        [1]=>
        string(14) "db2jcc_applica"
        [2]=>
        int(11448)
        [3]=>
        string(29) "10.0.0.209.51407.120606004536"
      }
      [2]=>
      array(4) {
        [0]=>
        string(8) "DB2INST1"
        [1]=>
        string(14) "db2jcc_applica"
        [2]=>
        int(13762)
        [3]=>
        string(29) "10.0.0.206.57473.120606024909"
      }
      [3]=>
      array(4) {
        [0]=>
        string(5) "ADMIN"
        [1]=>
        string(14) "db2jcc_applica"
        [2]=>
        int(15220)
        [3]=>
        string(29) "10.0.0.210.52248.120606045402"
      }
      [4]=>
      array(4) {
        [0]=>
        string(8) "DB2INST1"
        [1]=>
        string(8) "php-fpm:"
        [2]=>
        NULL
        [3]=>
        NULL
      }
      [5]=>
      &array(4) {
        [0]=>
        string(8) "DB2INST1"
        [1]=>
        string(14) "db2jcc_applica"
        [2]=>
        int(16547)
        [3]=>
        string(29) "10.0.0.202.52042.120606065813"
      }
    }
    

    【讨论】:

    • 看起来比 preg_split("/[\s]+/", $input); 还要简单
    • 正如所写,它已被用于格式化字符串解析。一个空格代表一个或多个空格。有一天我会写一篇关于它的更长的博客文章,因为它不太为人所知,但确实是一些方便的功能。
    • 请注意,对于“应用程序名称”=php-fpm: pool,您的示例无法正常工作。请注意应用程序名称中的空格。如果您检查您的演示,那么您会看到行的倒数第二个元素具有索引 2 和 3 为空的元素。它不应该为空,而是 16546 和 127.0.0.2.35530.120606065726。知道如何解决这个问题吗?
    • 是的,空格终止 sscanf 中的字符串。你可以开始制定可以接受的字符类(不是你的情况),你可以检查返回的数量(这里你需要 4,但只得到 2)并运行替代模式等。但是,正如你有那里有一个空间,你需要一些更复杂的解析器。我不知道这种情况,否则我会强调这个缺点。
    • sscanf 还支持固定数量的字符。看起来你的输出是这样格式化的。然后,您可以使用rtrim 函数删除尾随空格。
    【解决方案2】:

    你可以按空格preg_split

    $words = preg_split("/[\s]+/", $input);
    
    //if your lines seperated by `\n` new line you could:
    $inputArr = preg_split("/\R+/", $input);
    foreach($inputArr as $value) {
       $out = preg_split("/\s+/", $value);
       var_dump($out);
    }
    
    Thanks
    

    【讨论】:

    • +1 您可以先通过preg_split /\R+/ 获取行(\R 表示 unicod 安全新行),然后通过 /\s+/(您不需要大括号)跨度>
    • 它不适用于“应用程序名称”=php-fpm: pool。请注意应用程序名称中的空格。
    • 是的,我现在明白了,问题是没有格式可以如何将列分隔为空间。是否可以使用固定长度的列?所以例如:第一个需要 10 个字符,第二个需要 7 个字符,第三个需要 6 个字符等(带空格)。你必须有某种格式,你提到要用空格分隔。
    • 我解析的文本是 db2 命令的输出。我不确定我是否可以指望它是 100% 固定格式。我将此用作解决方法str_replace("php-fpm: ","php-fpm:",$line)
    • 我认为在空格上分割某些东西并不是解析“固定宽度”文件。拆分固定宽度的文件意味着根本没有分隔符,而是列号定义了数据字段。我发表评论是因为我来这里是为了寻找解决该问题的方法,而不是上述问题。
    【解决方案3】:

    您可以像这样在每条数据线上使用preg_match

    preg_match('~^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$~', $line, &$matches);
    

    如果匹配则返回1,否则返回0。 还有 - 更重要的是 - $matches 中的列内容,如下所示:

    array (
      0 => 'DB2INST1 db2jcc_applica 11446      10.0.0.209.51406.120606004531',
      1 => 'DB2INST1',
      2 => 'db2jcc_applica',
      3 => '11446',
      4 => '10.0.0.209.51406.120606004531',
    )
    

    该模式仅匹配由空白序列分隔的非空白序列。因此,只要数据本身没有空格,这应该适用于任何随机列长度。

    【讨论】:

      【解决方案4】:

      这是一篇对你有帮助的文章。

      //To parse an example like the following categorized columns:
      /*
      col1          col2    col3
      ====          ====    ====
      1 a b c d e   103     14 as d9
      2 a           103     14 as d9
      3 a           103     14 as d9
      */
      
      
      
      $headings = array('col1','col2','col3');
      $header = "col1 col2 col3";
      //get the $heading_pos_list by parsing the headings of each column with
      list($heading_pos_list, $lengths) = parse_heading($headings, $header);
      //Parse each line into a row structure
      $start_position = $heading_pos_list[0][$heading_key];
      $length_of_heading = $heading_pos_list[1][$heading_key];
      $line = '1 a b c d e 103 14 as d9';
      $row = parse_line($line, $headings, $start_position, $length_of_heading);
      //this works for each column and line
      echo $row('col1');
      //output:
      //1 a b c d e
      //continue on for each line.
      

      您可以在本文中找到这些功能: http://boulderapps.co/parsing-unevenly-spaced-columns-from-text-in-php

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-15
        • 1970-01-01
        • 2011-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多