Parse text containing ini-formatted data to php array

69

I have an API response in the following format

0000035901SM000000980000009800000125
0J0005              00064182
                    00000000
BEGIN
DATE=26.05.2015 09:01:48
SESSION=49500000031432619992
ERROR=0
RESULT=0
TRANSID=1000005699140

END
BEGIN SIGNATURE
iQBRAwkBAAD6tlVkDEwBAVOkAgCXHs1kj8u7E6tsdQLP8SFfkSDh9eYxkDYl/JdO
+2Lekurt2TfL68wxbCdaaWoT9Jy71luAvyAkgtNte/1FT22dsAHH
=GPcz
END SIGNATURE

I need to parse the texts between BEGIN and END into an array like

array(
'DATE'=>'26.05.2015 09:01:48',...
)

What is the best way to parse it. Also the content inside BEGIN/END can change.I wanted to create a generic function so that any key values inside BEGIN/END can be parsed out.

I have tried this:

function parseData(array &$lines)
{
    $result = array();                                 // this is where the current block is stored

    // Process one line at a time...
    do {
        $l = trim(array_shift($lines));                // extract the first line into $l (and remove it from $lines)
        $p = str_getcsv($l, ' ', '"');                 // split $l into words (take care of strings eclosed in quotes)

        $key = array_shift($p);                        // get the first word from the line
        switch ($key)
        {
        default:                                       // simple "key value" lines
            $result[$key] = implode(' ', $p);          // combine the remaining words from $p into a single string
            break;

        case 'BEGIN':                                  // start a new block
            $key = array_shift($p);                    // the real key in the array follows the 'BEGIN' keyword
            if (end($p) == 'END') {                    // check if the entire block is on a single line
                array_pop($p);                         // remove 'END' from the end of the array
                if (count($p) == 1) {                  // only one word remaining in $p:
                     $result[$key] = array_shift($p);  //              it is the value
                } else {                               // more than one word in $p: this is a list of properties
                     $aa = array();                    // put the values of this one-line block here
                     while (count($p) > 1) {
                         $k = array_shift($p);         // they come in pairs: key followed by value
                         $v = array_shift($p);
                         $aa[$k] = $v;
                     }
                     $result[$key] = $aa;              // the entire line was parsed; store it
                }
            } else {                                   // the last word on the line is not 'END'
                $result[$key] = parseData($lines);     // recursively call this function to parse the inner block and store its result
            }                                          // it will return after it consumes the line that starts with 'END'
            break;

        case 'END':                                    // here ends the block
            return $result;                            // return the collected values
        }

    } while (count($lines));                           // ... until there are no more lines to process

    return $result;                                    // no more lines to process; return the collected data
}
726

Answer

Solution:

The code is very easy

$lines = split("\n", $api);
while( ($l = trim(array_shift($lines))) != 'BEGIN' ); 
while( ($l = trim(array_shift($lines))) != 'END' )
  if ( preg_match('/^(\w+)=(.+)$/', $l, $matches) ) 
      ${$matches[1]}= $matches[2];
775

Answer

Solution:

Here's some code that is easier than easy code...

Essentially, use a regular expression to isolate the text between theBEGIN andEND markers, then parse the ini-formatted multiline string.

Code: (Demo)

preg_match('/^BEGIN$(.+?)^END$/ms', $text, $m);
var_export(parse_ini_string($m[1]));

Output:

array (
  'DATE' => '26.05.2015 09:01:48',
  'SESSION' => '49500000031432619992',
  'ERROR' => '0',
  'RESULT' => '0',
  'TRANSID' => '1000005699140',
)

Alternative code with no capture groups but same result: (Demo)

preg_match('/^BEGIN\K(?:\R.+)+(?=\R+END$)/m', $text, $m);
var_export(parse_ini_string($m[0]));

Honestly, even this one liner works by happenstance: (Demo)

var_export( 
    parse_ini_string(
        strstr($text, 'SIGNATURE', true)
    )
);
382

Answer

Solution:

The code is very easy

$lines = split("\n", $api);
while( ($l = trim(array_shift($lines))) != 'BEGIN' ); 
while( ($l = trim(array_shift($lines))) != 'END' )
  if ( preg_match('/^(\w+)=(.+)$/', $l, $matches) ) 
      ${$matches[1]}= $matches[2];
966

Answer

Solution:

Here's some code that is easier than easy code...

Essentially, use a regular expression to isolate the text between theBEGIN andEND markers, then parse the ini-formatted multiline string.

Code: (Demo)

preg_match('/^BEGIN$(.+?)^END$/ms', $text, $m);
var_export(parse_ini_string($m[1]));

Output:

array (
  'DATE' => '26.05.2015 09:01:48',
  'SESSION' => '49500000031432619992',
  'ERROR' => '0',
  'RESULT' => '0',
  'TRANSID' => '1000005699140',
)

Alternative code with no capture groups but same result: (Demo)

preg_match('/^BEGIN\K(?:\R.+)+(?=\R+END$)/m', $text, $m);
var_export(parse_ini_string($m[0]));

Honestly, even this one liner works by happenstance: (Demo)

var_export( 
    parse_ini_string(
        strstr($text, 'SIGNATURE', true)
    )
);

People are also looking for solutions to the problem: php - Boostrap thumbnail slider load dynamic conent

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.