如何从字符串中提取数字并添加到数组?

I want to convert this string:

<5> 20825.24 </ 5> <7> 0.0 </ 7> <8> 0.0 </ 8>

to an array with key value

I would really appreciate the help

I tried different xmlParse strategies but it is not exactly an xml.

$xml = new \SimpleXMLElement("<5>20825.24</5><7>0.0</ 7><8>0.0</8>");

Response: String could not be parsed as XML

I expect an array like this:

[5=>20825.24,7=>0.0,8=>0.0]
<?php

$subject = '<5> 20825.24 <7> 0.0 <8> 0.0';
$pattern = '/\<(\d)\>\s+(\d+\.\d+)/u';
$result = preg_match_all($pattern,$subject,$output);

$numbers = $output[1];
$output = $output[2];
$outTotal = [];

foreach ($numbers as $key => $number) {
    $outTotal[$number] = $output[$key];
}
var_dump($outTotal);

gives:

array(3) {
  [5]=>
  string(8) "20825.24"
  [7]=>
  string(3) "0.0"
  [8]=>
  string(3) "0.0"
}

As long as your output has numbers at the start of the XML tag name, it won't be valid XML. You may have to resort to using a regex to do the job.

This uses <(\d*)>(.*?)</~ which looks for a < followed by digits, then the > and captures everything up till the next </. It then combines the values from capture group 1 (the tag name) and 2 (the value)...

$data = "<5>20825.24</5><7>0.0</ 7><8>0.0</8>";

preg_match_all("~<(\d*)>(.*?)</~", $data, $matches);
$output = array_combine($matches[1], $matches[2]);
print_r($output);

gives...

Array
(
    [5] => 20825.24
    [7] => 0.0
    [8] => 0.0
)

Here, we can also use a regular expression and collect our desired numbers, then push it to a new array:

(?:<)(\d?)(?:>)(?:.+?)([0-9.]+)?

This expression might also work with nested elements.

Test

$re = '/(?:<)(\d?)(?:>)(?:.+?)([0-9.]+)?/m';
$str = '<5> 20825.24 </ 5> <7> 0.0 </ 7> <8> 0.0 </ 8>';
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

$arr = array();
foreach ($matches as $key => $value) {
    $arr[$value[1]] = $value[2];
}

var_dump($arr);

Output

array(3) {
  [5]=>
  string(8) "20825.24"
  [7]=>
  string(3) "0.0"
  [8]=>
  string(3) "0.0"
}

DEMO

RegEx Circuit

jex.im visualizes regular expressions:

enter image description here

If you want to match the digits in the opening tag with the digits in the closing tag, you could use a regex make use of a backreference to the first capturing group:

<(\d+)>\h*\d+(?:\.\d+)?\h*</\h*\1>

Explanation

  • < Match > char
  • (\d+)> Capture in group 1 matching 1+ digits and match >
  • \h* Match 0+ horizontal whitespace chars
  • \d+(?:\.\d+)? Match 1+ digits followed by an optional part to match a dot and 1+ digits
  • \h* Match 0+ horizontal whitespace chars
  • < Match <
  • /\h* Match \ followed by 0+ horizontal whitespace chars
  • \1> Match backreference to group 1 using \1 and match >

Regex demo | Php demo

For example:

$re = '~<(\d+)>\h*(\d+(?:\.\d+)?)\h*</\h*\1>~m';
$str = '<5> 20825.24 </ 5> <7> 0.0 </ 7> <8> 0.0 </ 8>';
preg_match_all($re, $str, $matches);
print_r(array_combine($matches[1], $matches[2]));

Result

Array
(
    [5] => 20825.24
    [7] => 0.0
    [8] => 0.0
)

Note that now the array keys are 5, 7 and 8. Keep in mind that if you might use different data, that arrays can not have duplicate keys.