Portal > Foren > PHP > PHP-Programmierung > Werte im Text ersetzen
Antwort
 
Themen-Optionen
Alt 05.03.2007, 13:49 Nach oben    #1
Bastian Fenske
 
Registriert seit: 04.01.2006
Ort: Kassel
Beiträge: 826
Standard Werte im Text ersetzen

Hi.

Ich hab hier eine kleine Funktion, um Platzhalter in Strings zu ersetzen.
Das Ganze funktioniert ohne RegExps, sondern splittet den String in Arrays, deren Felder dann nach und nach ersetzt werden.

Scheint mir aber sehr aufwändig zu sein dieses Verfahren und ich würde mich über flottere Lösungen freuen. Die Texte, um die es da geht sind hauptsächlich ein, zwei, drei Sätze lang und in den meisten Fällen muss gar nichts ersetzt werden.

Rudimentäre Tests und damit das benötigte Verhalten ist im Code unten enthalten. Nochmal kurz zusammengefasst:

Variablen: %test%
Prozentzeichen: \%
Backslashes: \\
Nicht angegebene Variablen sollen bestehen bleiben, also nicht rausgelöscht bzw. durch einen leeren String ersetzt werden.

Basti

PHP-Code:
<?php

function substitute($sString$aValues = array())
{
    if (
false === (strpos($sString'%')) || empty($aValues))
        return 
$sString;

    
$aBackslashSepParts explode('\\\\'$sString);

    foreach (
$aBackslashSepParts as $i => $sPart)
        
$aBackslashSepParts[$i] = explode('\%'$sPart);

    foreach (
$aValues as $sKey => $sValue) {

        foreach (
$aBackslashSepParts as $i => $aPercentSignSepParts) {

            foreach (
$aPercentSignSepParts as $j => $sPart)
                
$aBackslashSepParts[$i][$j] = str_replace("%$sKey%"$sValue$sPart);
        }
    }
    foreach (
$aBackslashSepParts as $i => $aPercentSignSepParts)
        
$aBackslashSepParts[$i] = implode('%'$aPercentSignSepParts);

    return 
implode('\\'$aBackslashSepParts);
}
$aTest = array(

    array(
'', array(), ''),
    array(
''null''),
    array(
'x', array('test' => 'y'), 'x'),
    array(
'%test%', array('test' => 'xxx'), 'xxx'),
    array(
'%test%%test%', array('test' => 'xxx'), 'xxxxxx'),
    array(
'%test%test%', array('test' => 'xxx'), 'xxxtest%'),
    array(
'\%test%', array('test' => 'xxx'), '%test%'),
    array(
'\\\\%test%', array('test' => 'xxx'), '\xxx'),
    array(
'\\\\\%test%', array('test' => 'xxx'), '\%test%'),
    array(
'%test%'null'%test%'),
    array(
'%foo%%bar%', array('test' => 'xxx''foo' => 'hello ''bar' => 'world!'), 'hello world!')
);

echo 
'<pre>';
foreach (
$aTest as $aTestValues) {

    list(
$sString$aValues$sExpected) = $aTestValues;
    
$sResult substitute($sString$aValues);
    print 
$sResult === $sExpected
        
"ok\n"
        
"nok ('$sResult' !== '$sExpected')\n";
}

Geändert von Basti (05.03.2007 um 13:55 Uhr).
Basti ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 05.03.2007, 14:09 Nach oben    #2
Erfahrener Benutzer
 
Registriert seit: 18.03.2005
Beiträge: 591
Standard

Ohne Regex, aber dafür recht oft foreach() ...
CIX88 ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 05.03.2007, 15:13 Nach oben    #3
Blubb... öfz
 
Benutzerbild von ljungi
 
Registriert seit: 16.03.2006
Ort: Berlin
Beiträge: 419
Standard

Genau, was spricht gegen Regex?
__________________
Vive la France! Welcome to Sarkoworld...
ljungi ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 05.03.2007, 15:47 Nach oben    #4
Bastian Fenske
 
Registriert seit: 04.01.2006
Ort: Kassel
Beiträge: 826
Standard

War nicht als Qualitätsmerkmal gemeint, dass ich keinen RegExp verwendet hab. Mir ist da nur kein gescheiter Ansatz eingefallen. Könnt ihr mir hier helfen?

Ein anderer Ansatz, den ich bei sowas öfter verwendet hab ist, die Sonderzeichen erstmal durch Zeichen zu ersetzen, die im Text nicht vorkommen und hinterher wieder "zurück zu übersetzen".

Basti
Basti ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 05.03.2007, 19:05 Nach oben    #5
Jonas
 
Benutzerbild von Artemis
 
Registriert seit: 03.06.2006
Beiträge: 240
Standard

Ich würde ein preg_replace_callback benutzen - scheint mir am sinnvollsten.
__________________
Applikations-Programmierung:
BlitzMax, BlitzPlus

Webentwicklung:
PHP, (X)HTML, CSS, JavaScript, MySQL


Artemis ist gerade online  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 06.03.2007, 12:11 Nach oben    #6
Bastian Fenske
 
Registriert seit: 04.01.2006
Ort: Kassel
Beiträge: 826
Standard

...und mit welchem Suchmuster?

Ich steh echt auf dem Schlauch, wie man dieses Escaping hinbekommen kann.

Basti
Basti ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 06.03.2007, 18:36 Nach oben    #7
Jonas
 
Benutzerbild von Artemis
 
Registriert seit: 03.06.2006
Beiträge: 240
Standard

Sowas ähnliches:
Code:
[^\\](\\\\)*%([a-zA-Z]+)%
EDIT: In einem PHP-String natürlich die \ noch einmal escapen.
__________________
Applikations-Programmierung:
BlitzMax, BlitzPlus

Webentwicklung:
PHP, (X)HTML, CSS, JavaScript, MySQL



Geändert von Artemis (06.03.2007 um 18:49 Uhr).
Artemis ist gerade online  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 06.03.2007, 19:12 Nach oben    #8
Daniel Golowin
 
Registriert seit: 17.11.2005
Ort: Rheinland-Pfalz, Osthofen
Beiträge: 122
Standard

Eine Möglichkeit:
PHP-Code:
$string "Text beginn%foo% und %xxx% weiter \\%foo%\\ und noch bisl %bar%foo%Text \%bar\% fertig.";

$replacements = Array(
    
'foo' => "wert1",
    
'bar' => "wert2"
);

function 
my_function($array)
{
    global 
$replacements;

    if ( (
$array[1] != '\%' && $array[3] != '\%')
        && 
array_key_exists($array[2], $replacements) )
    {
        if (
$array[1] == '\\%')    $array[1] = "\\";
        else                       
$array[1] = "";
        
        if (
$array[3] == '\\%')    $array[3] = "\\";
        else                       
$array[3] = "";
        

        return 
$array[1] . $replacements$array[2] ] . $array[3];
    }
    else
    {
        return 
$array[1] . $array[2] . $array[3];
    }
}

$pattern '/([\\]{2}%|[\\]{1}%|(?<!\\)%)(\w+?)([\\]{2}%|[\\]{1}%|(?<!\\)%)/';
$result preg_replace_callback($pattern'my_function'$string);

echo 
$result
Ist zwar etwas Wüst, aber der Ansatz glaube ich ist verständlich. Wenn ich natürlich deine Anforderung richtig verstanden hab?



EDIT: Sorry, hab da noch etwas drüber nachgedacht. Jetzt stimmt die Funktion.

Ersetzungen:
Code:
%foo%%bar% => wert1wert2
\\%foo\\%  => \wert1\
\\%foo%\\  => \wert\\
\%foo\%    => \%foo\%
\%foo%     => \%foo%
Das Verhalten der Funktion kannst du ja ändern!
Code:
array[1]  =  \\%  oder  \%  oder  %
array[3]  =  \\%  oder  \%  oder  %
array[2]  =  Wert zwischen array[1] und array[3]


EDIT nochmal:
Merkwürdig, wenn ich mein RegEx beim RegEx-Tester eingebe, dann funktioniert alles:
http://www.regex-tester.de/regex4_20070306205844.html

Wenn ich es aber lokal ausführe, kommt:
Code:
Warning: preg_replace_callback(:( Compilation failed: missing terminating ] for character class at offset 56 in D:\Programme\xampp\htdocs\projects\tests\- on line 36

Geändert von dago (06.03.2007 um 21:06 Uhr).
dago ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 07.03.2007, 00:46 Nach oben    #9
Daniel Golowin
 
Registriert seit: 17.11.2005
Ort: Rheinland-Pfalz, Osthofen
Beiträge: 122
Standard

@Basti
Jetzt glaube ich weiß was dein Problem war/ist. (EDIT bzw. nur meins )
Zitat:
Zitat von Artemis
In einem PHP-String natürlich die \ noch einmal escapen.
Klar weiß man das. Aber irgendwie komm man nicht drauf, dass die Werte gleich ausgewährtet werden:
PHP-Code:
$string '\%'// ist \%
$string '\\%'// ist \%
$string '\\\%'// ist \\%
$string '\\\\%'// ist \\% 
Also das richtige Pattern für mein Beispiel ist:
PHP-Code:
$pattern '/([\\\\]{2}%|[\\\\]{1}%|(?<!\\\\)%)(\\w+?)([\\\\]{2}%|[\\\\]{1}%|(?<!\\\\)%)/'
So und wenn man jetzt testen will, wie das sich verhält, dann muss man bei den Strings, die direkt im PHP-Code auftauchen dies beachten:
PHP-Code:
// %foo% siet so aus
$string "Text %foo% und weiter ...";

// \%foo\%
$string "Text \%foo\% und weiter ..."// oder
$string "Text \\%foo\\% und weiter ...";

// \\%foo\\%
$string "Text \\\%foo\\\% und weiter ..."// oder
$string "Text \\\\%foo\\\\% und weiter ..."
Dies muss man aber nur bei Strings beachten, die direkt im PHP-Code eingegeben werden. Bei Templates die aus der DB oder aus Dateien ausgelesen werden tritt dieses Problem natürlich nicht auf! (Ebenso beim Formularen, wie beim Regex-Tester)

Ok, jetzt hab ich auch was dabei gelernt. *g*

Geändert von dago (07.03.2007 um 00:51 Uhr).
dago ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Antwort

Lesezeichen


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Werte in einen Regexp einsetzen. ex³ PHP-Programmierung 6 02.02.2007 07:27
Probleme mit RSS heohni PHP-Programmierung 21 13.10.2006 12:10
Text hinter einem Bild mittig positionieren florian HTML, XML und CSS 3 13.09.2006 21:28
Bild im Text mit css? code5 HTML, XML und CSS 11 20.12.2005 13:15
dateisystem, Text an erste Position anhängen Niedi PHP-Programmierung 15 28.10.2005 20:59


Alle Zeitangaben in WEZ +2. Es ist jetzt 18:17 Uhr.


Powered by vBulletin® Version 3.7.3 (Deutsch)
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44