Reputation: 774
I have this RegEx:
^(?:([0-9]+) X,)?(?: )?(?:([0-9]+) Y,)?(?: Z)?$
What I do is check the following Patterns:
66 X, 55 Y, Z
66 X, 55 Y,
66 X, Z
55 Y, Z
66 X,
55 Y,
Group 1
is 66 X,
Group 2
is 55 Y,
What I want to do is to pull the values and checking it using something like this:
if (isset($group_1)) {
echo $group_1;
} else {
echo 'null';
}
echo ' - ';
if (isset($group_2)) {
echo $group_2;
} else {
echo 'null';
}
To get results like the following according to the patterns:
66 - 55
66 - 55
66 - null
null - 55
66 - null
null - 55
How Can I do that using PHP
?
Upvotes: 4
Views: 57
Reputation: 47874
Because your task seems to be extraction and not validation, you don't need to check for the start or end anchors nor the Z
component.
As the pattern allows all targeted substrings to be optional, you will need to check if a given element exists and is not an empty string. This is because when preg_match()
finds Y
but no X
, it will create an empty element in [1]
Alternatively, if preg_match()
finds X
but no Y
, no empty [2]
element will be generated.
Your input data is slightly ambiguous; I am assuming your are dealing with separate strings, but the overarching technique remains the same.
Code: (Demo)
$inputs = [
'66 X, 55 Y, Z',
'66 X, 55 Y,',
'66 X, Z',
'55 Y, Z',
'66 X,',
'55 Y',
'44 Z'
];
foreach ($inputs as $input) {
if (preg_match('~(?:(\d+) X)?,? ?(?:(\d+) Y)?~', $input, $out)) {
echo (isset($out[1]) && $out[1] !== '') ? $out[1] : 'null'; // if zero is a project-impossibility, only use !empty()
echo " - ";
echo isset($out[2]) ? $out[2] : 'null';
echo "\t\t\t(from: $input)\n";
}
}
Output:
66 - 55 (from: 66 X, 55 Y, Z)
66 - 55 (from: 66 X, 55 Y,)
66 - null (from: 66 X, Z)
null - 55 (from: 55 Y, Z)
66 - null (from: 66 X,)
null - 55 (from: 55 Y)
null - null (from: 44 Z)
Upvotes: 1
Reputation: 15464
I will rather do it with normal array function. Explanations are given as comments on code below
<?php
$str="66 X, 55 Y, Z
66 X, 55 Y,
66 X, Z
55 Y, Z
66 X,
55 Y,";
//remove all Zs as it is not needed here
$str=str_replace("Z","",$str);
//split the string with new line
$arr=explode("\n",$str);
$final=array();
foreach($arr as $val){
//remove white spaced entry
$inner_arr=array_filter(array_map('trim',(explode(",",$val))));
//if it has only one entry fill the array with either x on 1st or y on the last,remember it is always array of size 2, we have already removed whitespace and z entry
if(count($inner_arr)==1){
//fill with x of y
//if 1st entry is not X , fill 1st entry with X
if(strpos($inner_arr[0],'X')===false){
array_unshift($inner_arr,'NULL X');
}
//otherwise fill last entry with Y
else{
array_push($inner_arr,'NULL Y');
}
}
//print_r($inner_arr);
//replace x and y with blank value
array_push($final,str_replace(array('X','Y'),'',(implode("-",$inner_arr))));
}
//join them back with new line
$final_str=implode("\n",$final);
echo $final_str;
?>
output
66 -55
66 -55
66 -NULL
NULL -55
66 -NULL
NULL -55
working fiddle http://phpfiddle.org/main/code/8bk5-k3u1
Upvotes: 1
Reputation: 48711
With a preg_match(_all)?
function you have an array as returning value. You could work with that array this way:
// An unnecessary non-capturing group removed
$re = '/^(?:([0-9]+) X,)? ?(?:([0-9]+) Y,)?(?: Z)?$/m';
// Preparing feeds
$str = <<<_
66 X, 55 Y, Z
66 X, 55 Y,
66 X, Z
55 Y, Z
66 X,
55 Y,
\n
_;
// `PREG_SET_ORDER` flag is important
preg_match_all($re, $str, $matches, PREG_SET_ORDER);
// Iterate over matches
foreach ($matches as $match) {
// Remove first value off array (whole match)
unset($match[0]);
// Add `null` to existing empty value or the one that is not captured
foreach (['null', 'null'] as $key => $value) {
if (!isset($match[$key + 1]) || $match[$key + 1] === '')
$match[$key + 1] = $value;
}
// Implode remaining values
echo implode(" - ", $match), PHP_EOL;
}
Output (Live demo):
66 - 55
66 - 55
66 - null
null - 55
66 - null
null - 55
null - null
Upvotes: 2