php - 如何使用等号=符号的字符串值从数组中提取值而不使用preg_match

I have received a response from server as a string, which I converted as array, but still I am not able to make out, how I can access values from this array like

myarrray['txn_status'];

as also from the string clnt_rqst_meta

array(13) {
  [0]=>
  string(15) "txn_status=0399"
  [1]=>
  string(15) "txn_msg=failure"
  [2]=>
  string(55) "txn_err_msg=Transaction Cancelled : ERROR CODE TPPGE161"
  [3]=>
  string(17) "clnt_txn_ref=9178"
  [4]=>
  string(15) "tpsl_bank_cd=NA"
  [5]=>
  string(19) "tpsl_txn_id=T245107"
  [6]=>
  string(14) "txn_amt=121.00"
  [7]=>
  string(47) "clnt_rqst_meta={mob:9937253528}{custname:pawan}"
  [8]=>
  string(16) "tpsl_txn_time=NA"
  [9]=>
  string(15) "tpsl_rfnd_id=NA"
  [10]=>
  string(10) "bal_amt=NA"
  [11]=>
  string(47) "rqst_token=cd3f6f55-5990-4c3b-bb12-238eede827a0"
  [12]=>
  string(45) "hash=3cf25909ec73865d3200bc267119d3fcc21df463"
}

I know that the same can be achieved using regex/preg_match, but I am sure there must be some straight forward way to achieve it.

update: the actual string received from response is like this:

string(342) "txn_status=0399|txn_msg=failure|txn_err_msg=Transaction Cancelled : ERROR CODE TPPGE161|clnt_txn_ref=9178|tpsl_bank_cd=NA|tpsl_txn_id=T245107|txn_amt=121.00|clnt_rqst_meta={mob:9937253528}{custname:pawan}|tpsl_txn_time=NA|tpsl_rfnd_id=NA|bal_amt=NA|rqst_token=cd3f6f55-5990-4c3b-bb12-238eede827a0|hash=3cf25909ec73865d3200bc267119d3fcc21df463" 

so I used $response =explode("|",$response_str);

You could let the PHP function parse_str() do the heavy lifting for you but it expects to receive a standard query string, with the entries separated by &. Your input string uses a different separator (|) and parse_str() does not provide a way to tell it what character to use as separator.

The problem has a very simple solution: use str_replace() to replace | to & in the input string then pass the result to parse_str():

$input = 'txn_status=0399|txn_msg=failure|txn_err_msg=Transaction Cancelled : ERROR CODE TPPGE161|clnt_txn_ref=9178|tpsl_bank_cd=NA|tpsl_txn_id=T245107|txn_amt=121.00|clnt_rqst_meta={mob:9937253528}{custname:pawan}|tpsl_txn_time=NA|tpsl_rfnd_id=NA|bal_amt=NA|rqst_token=cd3f6f55-5990-4c3b-bb12-238eede827a0|hash=3cf25909ec73865d3200bc267119d3fcc21df463';
parse_str(str_replace('|', '&', $input), $output);

print_r($output);

It produces:

Array
(
    [txn_status] => 0399
    [txn_msg] => failure
    [txn_err_msg] => Transaction Cancelled : ERROR CODE TPPGE161
    [clnt_txn_ref] => 9178
    [tpsl_bank_cd] => NA
    [tpsl_txn_id] => T245107
    [txn_amt] => 121.00
    [clnt_rqst_meta] => {mob:9937253528}{custname:pawan}
    [tpsl_txn_time] => NA
    [tpsl_rfnd_id] => NA
    [bal_amt] => NA
    [rqst_token] => cd3f6f55-5990-4c3b-bb12-238eede827a0
    [hash] => 3cf25909ec73865d3200bc267119d3fcc21df463
)

See it in action: https://3v4l.org/KBaof

Warning

The solution exposed above works fine only if the input string does not contain & and %. These characters are special in query strings, parse_str() tries to interpret them using their special meaning and the code above breaks.

A solution that works when & or % is present in the input string

$input = 'txn_status=0399|txn_msg=failure|txn_err_msg=Transaction Cancelled : ERROR CODE TPPGE161|clnt_txn_ref=9178|tpsl_bank_cd=NA|tpsl_txn_id=T245107|txn_amt=121.00|clnt_rqst_meta={mob:9937253528}{custname:pawan}|tpsl_txn_time=NA|tpsl_rfnd_id=NA|bal_amt=NA|rqst_token=cd3f6f55-5990-4c3b-bb12-238eede827a0|hash=3cf25909ec73865d3200bc267119d3fcc21df463';
$output = array_reduce(
    explode('|', $input),
    function($acc, $item) {
        list($key, $value) = explode('=', $item, 2);
        $acc[$key] = $value;
        return $acc;
    },
    []
);

print_r($output);

It still fails if | is present in the values (e.g. ...|txn_err_msg=a|b|clnt_txn_ref=...) but this issue doesn't have a solution because of the naive encoding of the input string.

If you can modify the server that produces the input data, change it to produce JSON output. JSON is a format that allows validation of the input string and PHP provides functions to encode and decode it. The code becomes cleaner on both sides.

Try this:

$newArray = [];
foreach ($myArray as $element) {
    $exploded = explode('=', $element);
    $newArray[$exploded[0]] = $exploded[1];
}

I'm guessing that this expression might return the desired matches:

([^=]+)=([^=]+)(?:\||$)

Test

$re = '/([^=]+)=([^=]+)(?:\||$)/m';
$str = 'txn_status=0399|txn_msg=failure|txn_err_msg=Transaction Cancelled : ERROR CODE TPPGE161|clnt_txn_ref=9178|tpsl_bank_cd=NA|tpsl_txn_id=T245107|txn_amt=121.00|clnt_rqst_meta={mob:9937253528}{custname:pawan}|tpsl_txn_time=NA|tpsl_rfnd_id=NA|bal_amt=NA|rqst_token=cd3f6f55-5990-4c3b-bb12-238eede827a0|hash=3cf25909ec73865d3200bc267119d3fcc21df463';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

var_dump($matches);

The expression is explained on the top right panel of this demo if you wish to explore/simplify/modify it.

This any help?

$string = "txn_status=0399|txn_msg=failure|txn_err_msg=Transaction Cancelled : ERROR CODE TPPGE161|clnt_txn_ref=9178|tpsl_bank_cd=NA|tpsl_txn_id=T245107|txn_amt=121.00|clnt_rqst_meta={mob:9937253528}{custname:pawan}|tpsl_txn_time=NA|tpsl_rfnd_id=NA|bal_amt=NA|rqst_token=cd3f6f55-5990-4c3b-bb12-238eede827a0|hash=3cf25909ec73865d3200bc267119d3fcc21df463";
txn_status = ""; 
foreach(explode('|', $string) as $val){
    $temp = explode('=', $val);
    //$temp[0] is left side of =
    //$temp[1] is right side of =
    if($temp[0] == "txn_status"){
        txn_status = $temp[1];
    }
}

you also can use sscanf. this is not regex but still using some pattern but is more clean than preg_match

$arr = ['key1=value1', 'key2=value2', 'key3=value3'];

foreach ($arr as $str) {
    sscanf($str, "%[^=]=%[^=]", $key, $value);
    echo "[$key => $value]";
}