1

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

    )
)                      
5
  • 2
    What is the desired output for the inputs you have specified? Commented Sep 5, 2018 at 1:16
  • you can use fopen('php://temp', 'w+') put the string into temp with fwrite then use rewind and fgetc to count the chars tell you hit offset etc. etc. Stream wrapper if you prefer the file handles. Commented Sep 5, 2018 at 1:17
  • If you have some usable delimiters, you might look at strtok. Commented Sep 5, 2018 at 1:22
  • I have updated the question with the desired result Commented Sep 5, 2018 at 1:30
  • Can you update it to include more then just the header. array_combine works good on CSV (delimited stuff) most the time, well I would slap an array_fill_keys and array_replace on there. But yea. Commented Sep 5, 2018 at 1:33

2 Answers 2

2

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.....................................
)
Sign up to request clarification or add additional context in comments.

1 Comment

Like this - very portable
0

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!

7 Comments

The preriods '.' are unique to this report only - I want a portable solution for reports that dont have periods in the header
That begs the question what does the other ones have. Are they files to begin with, there is a lot of missing information. If the rest are CSV, I can show you how to fix this one to be CSV and read it the same as them.
For example is that whole file done in . dots or just the header. I can code most anything, and I'm bored right now.
It is a HTML document - column headers across the top, data in columns below. Here is a sample of another file I had to process - oi66.tinypic.com/1zob6f5.jpg
Thanks for telling me ... now ... have you tried PHPQuery it's a dom library that lets you use jQuery selectors to parse a page. HTML is like a whole other ball game,
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.