preg_split如何使用php将分隔符转换为索引

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.