I have this cases with strings in PHP: *nJohn*sSmith*fGeorge#*nHenry*sFord
and wish to create an array with
[name],[surname],[fathers] as indexes so it will produce
name_array[1] = (
[name] => 'John',
[surname] => 'Smith',
[fathers] => 'George'
)
name_array[2]=(
[name] => 'Henry',
[surname] => 'Ford'
)
and so on. How to do it using preg_split in PHP?? Thanks!
I'd use preg_match_all
to get the names. If your string is consistent I think you could do:
$string = '*nJohn*sSmith*fGeorge#*nHenry*sFord';
preg_match_all('/\*n(?<givenname>.*?)\*s(?<surname>.*?)(?:\*f(?<middlename>.*?))?(?:#|$)/', $string, $matches);
print_r($matches);
Regex demo: https://regex101.com/r/1hKzvM/1/
PHP demo: https://eval.in/784879
Solution without using regex:
$string = '*nJohn*sSmith*fGeorge#*nHenry*sFord';
$result = array();
$persons = explode('#', $string);
foreach ($persons as $person) {
$identials = explode('*', $person);
unset($r);
foreach ($identials as $idential) {
if(!$idential){
continue; //empty string
}
switch ($idential[0]) { //first character
case 'n':
$key = 'name';
break;
case 's':
$key = 'surename';
break;
case 'f':
$key = 'fathers';
break;
}
$r[$key] = substr($idential, 1);
}
$result[] = $r;
}
This function will produce the result that you want ! but consider it's not the only way and not the 100% correct way ! i used preg_split as u asked
function splitMyString($str){
$array_names = [];
$mainString = explode('#', $str);
$arr1 = preg_split("/\*[a-z]/", $mainString[0]);
unset($arr1[0]);
$arr1_values = array_values($arr1);
$arr1_keys = ['name','surname','fathers'];
$result1 = array_combine($arr1_keys, $arr1_values);
// second part of string
$arr2 = preg_split("/\*[a-z]/", $mainString[1]);
unset($arr2[0]);
$arr2_values = array_values($arr2);
$arr2_keys = ['name','surname'];
$arr2 = array_combine($arr2_keys, $arr2_values);
$array_names[] = $arr1;
$array_names[] = $arr2;
return $array_names;
}
// test result !
print_r(splitMyString("*nJohn*sSmith*fGeorge#*nHenry*sFord"));
thanks to all! For some reason the site blocks my voting for some 'reputation' reason which I find not-fully democracy compliant! On the other hand who cares about democracy these days! Nevertheless I am using solution #2, without indicating that solution 1 or 3 are not great! Regards.
However inspired by your answers I came up with mine also, here it is!
$string = '*nJohn*sSmith*fGeorge#*nHenry*sFord';
split_to_key ( $string, array('n'=>'Name','s'=>'Surname','f'=>'Middle'));
function split_to_key ( $string,$ind=array() )
{
$far=null;
$i=0;
$fbig=preg_split('/#/',$string,-1,PREG_SPLIT_NO_EMPTY);
foreach ( $fbig as $fsmall ) {
$f=preg_split('/\*/u',$fsmall,-1,PREG_SPLIT_NO_EMPTY);
foreach ( $f as $fs ) {
foreach( array_keys($ind) as $key ) {
if( preg_match ('/^'.$key.'/u',$fs ) ) {
$fs=preg_replace('/^'.$key.'/u','',$fs);
$far[$i][$ind[$key]]=$fs;
}
}
}
$i++;
}
print_r($far);
}
Like Chris, I wouldn't use preg_split()
. My method uses just one preg()
function and one loop to completely prepare the filtered output in your desired format (notice my output is 0-indexed, though).
Input (I extended your input sample for testing):
$string='*nJohn*sSmith*fGeorge#*nHenry*sFord#*nJames*sWashington#*nMary*sMiller*fRichard';
Method (PHP Demo & Regex Demo):
if(preg_match_all('/\*n([^*]*)\*s([^*]*)(?:\*f([^#]*))?(?=#|$)/', $string, $out)){
$out=array_slice($out,1); // /prepare for array_column()
foreach($out[0] as $i=>$v){
$name_array[$i]=array_combine(['name','surname','father'],array_column($out,$i));
if($name_array[$i]['father']==''){unset($name_array[$i]['father']);}
}
}
var_export($name_array);
Output:
array (
0 =>
array (
'name' => 'John',
'surname' => 'Smith',
'father' => 'George',
),
1 =>
array (
'name' => 'Henry',
'surname' => 'Ford',
),
2 =>
array (
'name' => 'James',
'surname' => 'Washington',
),
3 =>
array (
'name' => 'Mary',
'surname' => 'Miller',
'father' => 'Richard',
),
)
My regex pattern is optimized for speed by using "negative character classes". I elected to not use the named capture groups because they nearly double the output array size from preg_match_all()
and that array requires further preparation anyhow.