2014-10-28 4 views
6

Ich versuche, gemeinsam Masken aus einem String zu erstellen, wie so:Wie kann ich mehrere Zeichenfolgen in einer Zeichenfolge ohne überlappende Ergebnisse ersetzen?

012abc.d+e_fg~hijk => 012{start}.d+{middle}_fg~{end}jk 

ersetzen:

$arrFromTo = array(
       'st' => '{pre}', 
       'abc' => '{start}', 
       'e' => '{middle}', 
       'hi' => '{end}', 
       'dd' => '{post}' 
      ); 

Stattdessen halte ich Ersatz überlappende und stattdessen etwas wie diese erhalten (mit einer Schleife von str_replace ' e):

012{{pre}art}.d+{mi{post}le}_fg~{end}jk 

Da die st in der bereits gefunden wird ersetzt {start} und dd ist in {middle} gefunden.

Wie würden Sie das Folgende ersetzen?

$str = 'abc.d+e_fg~hijk'; 

echo replace_vars($str); // Desired output: 012{start}.d+{middle}_fg~{end}kJ 
+0

Ich dachte, das Array neu anzuordnen, so dass "dd" => "{post}" in einer anderen Position war, aber das brachte andere Probleme. –

+0

Es ist nicht oft, dass ich regex vorschlage, aber in diesem Fall könnte es ratsam sein, Lookahead/Behinds durchzuführen, um zu überprüfen, was Sie erwarten, bevor Sie ersetzen –

+0

@scrowler Leider gibt es einen Fehler in meiner PCRE-Bibliothek mit negativen Look-Backs variabler Länge. Ich kann die PCRE-Bibliothek nicht aktualisieren, daher habe ich an dieser Stelle den Pfad nicht mehr fortgesetzt. – Ryan

Antwort

6

Ich könnte missverstehen, aber Sie scheinen keine Regex für den Ersatz zu brauchen. Sie sind einfache, wörtliche Ersetzungen.

$from = '012abc.d+e_fg~hijk'; 
$arrFromTo = array(
       'st' => '{pre}', 
       'abc' => '{start}', 
       'e' => '{middle}', 
       'hi' => '{end}', 
       'dd' => '{post}' 
      ); 
$to = strtr($from, $arrFromTo); // 012{start}.d+{middle}_fg~{end}jk 

strtr() ist genial. Es benötigt eine sehr lesbare Eingabe und ersetzt nicht wie Ihr Problem in der Schleife.

2

Sie können preg_replace wie folgt verwenden:

$str = '012abc.d+e_fg~hijk'; 
$arrFromTo = array(
       'st' => '{pre}', 
       'abc' => '{start}', 
       'e' => '{middle}', 
       'hi' => '{end}', 
       'dd' => '{post}' 
      ); 

$reArr=array(); 
foreach($arrFromTo as $k=>$v){ 
    $reArr['/' . $k . '(?![^{}]*})/'] = $v; 
} 

echo preg_replace(array_keys($reArr), array_values($reArr), $str); 
//=> 012{start}.d+{middle}_fg~{end}jk 

Kern dieser regex ist diese negative lookaead: (?![^{}]*})

Welche passenden Schlüssel des Arrays vermeiden, wenn es in {...} da alle eingeschlossen ist Ersatzteile sind in {...} enthalten.

+0

Warum 'preg_replace'? Warum nicht "str_replace" oder "strtr"? Kein Regexing notwendig, oder? – Rudie

+0

Wie können Sie ein Lookahead in 'str_replace' verwenden? – anubhava

+1

Warum brauchst du Lookahead? Sie sind wörtliche Ersetzungen ... Es gibt keine '{' und '}' in der Quellzeichenfolge. – Rudie

0

Dies wird die Zeichenfolge für jeden Ersatz in der Reihenfolge suchen. Wenn es einen findet, teilt es die Zeichenfolge auf und sucht den Rest der Zeichenfolge für alle anderen Ersetzungen.

$str = '012abc.d+e_fg~hijk'; 

$rep = array(
    'st' => '{pre}', 
    'abc' => '{start}', 
    'e' => '{middle}', 
    'hi' => '{end}', 
    'dd' => '{post}' 
); 

$searched = ''; 

foreach ($rep as $key => $r) { 
    if (strpos($str, $key) !== false) { 

     $searched .= substr($str, 0, strpos($str, $key)) . $r; 
     $str = substr($str, strpos($str, $key) + strlen($key)); 

    } 
} 

$searched .= $str; 

echo $searched; //012{start}.d+{middle}_fg~{end}jk 

Es wird suchen und finden Sie sie in der Reihenfolge, die Sie angegeben haben.