donglaoping9702
2018-09-05 01:06
浏览 71
已采纳

PHP上的多个substr字符串

I have a string for which I am provided a string index.

I am creating a process to read it and I am wondering if there is a php function that exists that I have overlooked or an unaware of to perform this process far more easily.

$data:

Invoice No..... Sale Type Desc...... Misc Amt.... Misc Acc.. Misc Acc Desc.....................................

FOCF219611      CUSTOMER                    -0.02 8050       TOOLS & SUPPLIES - SERVICE
FOCF219669      CUSTOMER                   -14.49 8050       TOOLS & SUPPLIES - SERVICE

$fieldIndexes:

Array (
  [0] => 15 
  [1] => 20 
  [2] => 12 
  [3] => 10
  [4] => 50
)

Split $data into $headers array:

array_push($headers, substr($data, 0, $fieldIndexes[0]));
array_push($headers, substr($data, $fieldIndexes[0], $fieldIndexes[1]));
array_push($headers, substr($data, $fieldIndexes[1], $fieldIndexes[2]));
array_push($headers, substr($data, $fieldIndexes[2], $fieldIndexes[3]));
array_push($headers, substr($data, $fieldIndexes[3], $fieldIndexes[4]));

Is there a function that can remove part of a string - like array_shift for a string? I was thinking I could loop the $fieldIndexes, extract the first length from the start of the string, and so on until the string is empty and condense this into 3 lines and make it portable for any number of fieldIndexes?

Desired Result:

Array
(
[HEADERS] => Array
    (
        [0] => Invoice No
        [1] => Sale Type Desc
        [2] => Misc Amt
        [3] => Misc Acc
        [4] => Misc Acc Desc

    )

[1] => Array
    (
        [Invoice No] => FOCF219611
        [Sale Type Desc] => CUSTOMER
        [Misc Amt] => -0.02
        [Misc Acc] => 8050
        [Misc Acc Desc] => TOOLS & SUPPLIES - SERVICE

    )
)                      
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • douxiuyu2028 2018-09-05 01:38
    已采纳

    You can create a function like this one to split using the chunk sizes. Note: Since each size in the $fieldIndexes array didn't include the space between columns, I added one to each length (15+1, 20+1, ...)

    <?php
    
    $headerString ="Invoice No..... Sale Type Desc...... Misc Amt.... Misc Acc.. Misc Acc Desc.....................................";
    $fieldIndexes = [ 15+1, 20+1, 12+1, 10+1,  50+1];
    
    
    function getParts($string, $positions){
        $parts = array();
    
        foreach ($positions as $position){
            $parts[] = substr($string, 0, $position);
            $string = substr($string, $position);
        }
    
        return $parts;
    }
    
    print_r(getParts($headerString, $fieldIndexes));
    ?>
    

    Result:

    Array
    (
        [0] => Invoice No..... 
        [1] => Sale Type Desc...... 
        [2] => Misc Amt.... 
        [3] => Misc Acc.. 
        [4] => Misc Acc Desc.....................................
    )
    
    点赞 打赏 评论
  • dongou3286 2018-09-05 01:25

    Like this (because I said it in the comments)

    $str = 'Invoice No..... Sale Type Desc...... Misc Amt.... Misc Acc.. Misc Acc Desc.....................................';
    
    $f = fopen('php://temp', 'w+');
    fwrite($f, $str);
    rewind($f);
    $headers = [];
    
    $header = '';
    while(false !== ($c = fgetc($f))){
        if($c != '.'){
            $header .= $c;
        }elseif(!empty($header)){
            $headers[] = trim($header);
            $header = '';
        }
    }
    
    print_r($headers);
    

    Outputs

    Array
    (
        [0] => Invoice No
        [1] => Sale Type Desc
        [2] => Misc Amt
        [3] => Misc Acc
        [4] => Misc Acc Desc
    )
    

    Note I did this without using an offset, but I mentioned it in the comments and I like doing weird things like this. It's enjoyable.

    Of course you could just do this for the same result:

    $str = 'Invoice No..... Sale Type Desc...... Misc Amt.... Misc Acc.. Misc Acc Desc.....................................';
    
    print_r(array_filter(array_map('trim',explode('.', $str))));
    

    But that is far, far to easy.

    Sandbox

    And if you don't like the keys being all wacky you can just lap an array_values on that sucker.

     print_r(array_values(array_filter(array_map('trim',explode('.', $str)))));
    

    LOL, another monday.

    UPDATE

    You can use the file stream wappers to fix a file for CSV reading, too. In PHP5.4 (I think or 5.3) the SplFileObj is missing fgetcsv and I used a trick with them to patch that class.... :)

    This was my point (but there is a lot I don't know)

    $str = 'Invoice No..... Sale Type Desc...... Misc Amt.... Misc Acc.. Misc Acc Desc.....................................
    somedata .... someother stuff ... foobar ... hello ... world..
    ';
    
    //pretend this is a real file
    $f = fopen('php://temp', 'w+');
    fwrite($f, $str);
    rewind($f);
    $headers = [];
    $num_headers = 0;
    
    $i = 1;
    while(false !== ($c = fgetcsv($f))){
    
         //if there is only one element assume the delimiter is wrong
        if(count($c) == 1){
            //you could test the string for multiple delimiters and change
            /*
             if(strpos($c, '.')){
                $regex = '/\.+/'
             }else if(strpos($c, '~')){
                $regex = '/~+/'
             } etc....
            */
    
            //use memory buffer to fix files with .'s but still read them as
            //a normal CSV file, php://memory is really fast.
            //and this gives us all the parsing benefits of fgetcsv
            //you could use any delimiter here you want.
            $fixed =  trim(preg_replace('/\.+/', ',', $c[0]),',');
            $m = fopen('php://memory', 'w+');
            fwrite($m, $fixed);
            rewind($m);
            $c = fgetcsv($m);
        }
        //trim any spaces, not a bad idea anyway
        $c = array_map('trim', $c);
    
        //if no headers use the first line of file as the header
        if(empty($headers)){
            $headers = $c;
            //count them (see below)
            $num_headers = count($headers);
            continue;
        }
    
         //array_combine is a good choice for header => values
         //but the arrays have to be the same size
        if(count($c) != $num_headers) die("missing dilimter on line {$i}");
    
        $line = array_combine($headers, $c);
    
        //continue with normal csv opperation
        print_r($line);
    
        ++$i; //track the line number
    }
    

    Output

    Array
    (
        [Invoice No] => somedata
        [Sale Type Desc] => someother stuff
        [Misc Amt] => foobar
        [Misc Acc] => hello
        [Misc Acc Desc] => world
    )
    

    UPDATE

    As I mentioned in the comments (after finding out it was HTML). You can use a DOM parser. One I have used in the past is PHPQuery it's a bit dated now. But it's nice because you can use jQuery syntax. For example say you have this

    <ul id="title" >
        <li>header</li>
        <li>header</li>
        <li>header</li>
    </ul>
    

    You can find it with something like this (it's been a while, so if this is wrong sorry)

      $length =  $PHPQuery->find("#headers li")->lenght;
    
       for($i=0;$i<$lenght;++$i){
          echo $PHPQuery->find("#headers li:eq($i)")->text();
       }
    

    You can even pull attributes using ->attr('href') for example. Basically you can take advantage of the HTML structure and pull what you need instead of converting it to text and trying to remove a bunch of "stuff"

    Cheers!

    点赞 打赏 评论

相关推荐