SEO-Software von Suchmaschinenoptimierung.de

Suchen und Ersetzen mit Regex

(hier klicken, um zum Original Thread zu gelangen)
TrioxX
Hi,

ich stehe vor einem Problem... Ich habe mein Forum in ein anderes konvertiert, jedoch benutzen beide Softwares verschiedene Methoden zur Darstellung der Quotes.

So war es vorher:

code:
1:
[quote name='Tester' date='10 March 2010 - 08:13 PM' timestamp='1268251994' post='23413']


So ist es jetzt:

code:
1:
[QUOTE=Tester;23413]


Wie kriege ich nun sämtliche Beiträge, die der alten Form entsprechen, in die neue Form?

Jemand von euch vielleicht eine Idee?
moonsword
sind die attribute in der alten form immer in der gleichen reihenfolge?

edit: wenn die reihenfolge immer gleich ist, kann du das hier verwenden:
php:
1:
<?php preg_replace('/\[quote.*?name=(\'|"|)(.*?)\\1.*?post=(\'|"|)(.*?)\\3\.*?\]/is','[QUOTE=\\2;\\4]',$string?>


am anderen arbeite ich grade noch.

edit2: soooo, wenn es beliebig viele sind und die atrribute an unterschiedlichen stellen sein können, dann musst du beide einzeln parsen...die quotes rausparsen und dann aus dem string der attribute die einzelnen attribute rausparsen smile
hab ne kleine funktion geschrieben, die das alles macht...der kannst du sagen, was für ein string er bearbeiten soll, welches tag, rechts und links delimiter und dann noch, wie es nachher aussehen soll ein einzelner quote smile
bitte dran denken, dass alles eingeben in einen regex sind...d.h. sonderzeichen müssen so markiert werden, du kannst aber auch sachen modifien, die du nicht genau kennst smile

naja...das andere wird über ein str_replace gemacht...nur das suchen kann er so erledigen,

viel spass:
php:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
<?php
$string "[quote name='Tester2' date='15 March 2010 - 08:13 PM' timestamp='1268251994' post='1234'][quote name='Tester' date='10 March 2010 - 08:13 PM' timestamp='1268251994' post='23413']";

function modify($str,$tag,$delimiter,$tmp) {
    list($d_left,$d_right) = explode(';',$delimiter);

    preg_match_all('/'.$d_left.$tag.'(.*?)'.$d_right.'/is',$str,$match);

    for($i 0$i count($match[0]); $i++) {
        preg_match_all('/(\w+)=\'(.*?)\'/',$match[1][$i],$m);

        $m[1] = array_map(create_function('$e','return "{".$e."}";'),$m[1]);
        $str str_replace($match[0][$i],str_replace($m[1],$m[2],$tmp),$str);
    }
    return $str;
}
print modify($string,'quote','\[;\]','[QUOTE={name};{post}]');
?>


edit3: habs nochmal verschönert...nun parsed er nicht nur nach: ' ... sondern er kann auch ", und, wenn sie weggelassen werden:
php:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
<?php
$string "[quote name=Tester2 date='15 March 2010 - 08:13 PM' timestamp='1268251994' post='1234'][quote name='Tester' date='10 March 2010 - 08:13 PM' timestamp='1268251994' post='23413']";

function modify($str,$tag,$delimiter,$tmp) {
    list($d_left,$d_right) = explode(';',$delimiter);

    preg_match_all('/'.$d_left.$tag.'(.*?)'.$d_right.'/is',$str,$match);

    for($i 0$i count($match[0]); $i++) {
        preg_match_all('/(\w+)=(.*?)(?:\s|$)/is',$match[1][$i],$m);

        $m[1] = array_map(create_function('$e','return "{".$e."}";'),$m[1]);
        $m[2] = array_map(create_function('$e','return str_replace(array("\'","\""),"",$e);'),$m[2]);
        $str str_replace($match[0][$i],str_replace($m[1],$m[2],$tmp),$str);
    }
    return $str;
}
print modify($string,'quote','\[;\]','[QUOTE={name};{post}]');
?>


geht sicher noch schöner, ... das str_replace arbeitet absichtlich jedes mal...liegt daran, wenn man größere daten verarbeitet, dann ist das sinnvoller, weil sich dann kein riesen array aufbaut smile

naja...vielleicht kann man dan den array_map funktionen schon was verschönern
TrioxX
Hi,

danke dafür, sieht wirklich sehr gut aus. Jedoch hast du dir mehr Arbeits als nötig gemacht und vor lauter Code sehe ich den Wald nicht mehr großes Grinsen

Ich habe mal etwas gekramt und herausgefunden, wieso die Umwandlung nicht stattgefunden hat:

php:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
<?
            preg_match('#\[quote name=\'(.*)\' date=\'(.*)\' post=\'(.*)\'(.*)\](.*)\[/quote\]#siU'$text$matches);

            if ($matches[3])
            {
                $new_id $this->get_post_id($Db_target$target_database_type$target_table_prefix$matches[3]);

                $text str_replace($matches[0], "[QUOTE=" $matches[1] . ";{$new_id}]" trim($matches[5]) . "[/QUOTE]"$text);
            }
            else
            {
                return $text;
            }
        }
?>


Das kann nicht gehen, weil der Regex nicht zutrifft. Ich habe schon probiert und gewerkelt, aber das Ergebnis bleibt das Selbe.

Jetzt ist mir aufgefallen, dass ich zwei verschiedene Typen des Quote-Tags habe:

1.
code:
1:
[quote name='Tester' date='10 March 2010 - 08:13 PM' timestamp='1268251994' post='23413']DIES IST EIN TEST[/quote]


2.
code:
1:
[quote name='Tester' post='10208' date='Apr 12 2009, 03:09 PM']DIES IST EIN TEST[/quote]


Wobei letzteres aus einer noch älteren, jedoch nocht kompatiblen Version stammt.

Beide Versionen enthalten die einzigen beiden Dinge, die ich unter Berücksichtigung des o.g. Codes benötige:

name, post und der Text zwischen den Tags.

Alles Andere ist überflüssig bzw. für mein Vorhaben nicht relevant. Jedoch soll der obige Code den alten BBCode in die neue Form bringen und das tut er leider nicht.

Da ich zwei verschiedene Typen von Quote besitze, müsste ich also für beide zwei entsprechende Regex prüfen und die entsprechenden Werte extrahieren. Und da liegt leider mein Problem, weil ich von dem ganzen Regex-Kram leider nicht all zu viel verstehe, bzw. irgendwann nicht mehr durchsteige unglücklich

Aber wie gesagt... Danke schon einmal für deine Lösungen, die in einem anderem Anwendungsfall tadellos funktionieren. Bei meinem Falle muss ich schauen, dass ich mir das Ganze irgendwie zurecht schuster.

EDIT:

Okay... Mittlerweile glaube ich, dass ich es habe...

php:
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:
<?
            if(preg_match('#\[quote name=\'(.*)\' post=\'(.*)\' date=\'(.*)\'](.*)\[/quote\]#siU'$text$matches))
            {
                $name $matches[1];
                $post $matches[2];
                $content $matches[4];
            }
            elseif(preg_match('#\[quote name=\'(.*)\' date=\'(.*)\' timestamp=\'(.*)\' post=\'(.*)\'](.*)\[/quote\]#siU'$text$matches))
            {
                $name $matches[1];
                $post $matches[4];
                $content $matches[5];
            }
            
            if ($post)
            {
                $new_id $this->get_vb_post_id($Db_target$target_database_type$target_table_prefix$post);

                $text str_replace($matches[0], "[QUOTE=" $name ";{$new_id}]" trim($content) . "[/QUOTE]"$text);
            }
            else
            {
                return $text;
            }
?>
moonsword
die funktionen auch in deinem fall tadellos?
hättest du meine letzte funktion genommen? da den string reingetan und dann aufgerufen hätte er genau den effekt gehabt?

php:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
<?php function modify($str,$tag,$delimiter,$tmp) {
    list($d_left,$d_right) = explode(';',$delimiter);

    preg_match_all('/'.$d_left.$tag.'(.*?)'.$d_right.'/is',$str,$match);

    for($i 0$i count($match[0]); $i++) {
        preg_match_all('/(\w+)=(.*?)(?:\s|$)/is',$match[1][$i],$m);

        $m[1] = array_map(create_function('$e','return "{".$e."}";'),$m[1]);
        $m[2] = array_map(create_function('$e','return str_replace(array("\'","\""),"",$e);'),$m[2]);
        $str str_replace($match[0][$i],str_replace($m[1],$m[2],$tmp),$str);
    }
    return $str;
} ?>

aufgerufen mit:
php:
1:
<?php modify($string,'quote','\[;\]','[QUOTE={name};{post}]'); ?>
TrioxX
Im Prinzip hast du Recht und deine Funktion konnte mir doch helfen. Mir ist nur eine Sache aufgefallen:

code:
1:
[quote]


Hier wird die entsprechende Änderung erzwungen, dabei sollte diese Version übergangen werden.
moonsword
pfff das wusste ich nicht, dass du solche auch drin hast...ja stimmt...da wird ne änderung erzwungen, aber das ist ja gering...das ist eine kleine if-anweisung?
TrioxX
Auch richtig.

Ich habs jetzt so:

php:
1:
<?php if (strpos($text'[quote') !== false && strpos($text'[quote]') !== true?>


In der Hoffnung, dass es funktioniert fröhlich
moonsword
verbesserte Version smile
php:
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:

<?php
$string "[quote]text[/quote]";
///*
function modify($str,$tag,$delimiter,$tmp,$attr) {
    list($d_left,$d_right) = explode(';',$delimiter);

    preg_match_all('/'.$d_left.$tag.'(.*?)'.$d_right.'(.*?)'.$d_left.'\/'.$tag.$d_right.'/is',$str,$match);

    for($i 0$i count($match[0]); $i++) {
        preg_match_all('/(\w+)=(.*?)(?:\s|$)/is',$match[1][$i],$m);

        if(count($m[0]) > 0) {
            $m[1] = array_map(create_function('$e','return "{".$e."}";'),$m[1]);
            $m[2] = array_map(create_function('$e','return str_replace(array("\'","\""),"",$e);'),$m[2]);
            $attr str_replace($m[1],$m[2],$attr);
        } else $attr '';

        $str str_replace($match[0][$i],str_replace(array('{attributes}','{text}'),array($attr,$match[2][$i]),$tmp),$str);
    }
    return $str;
}
print modify($string,'quote','\[;\]','[QUOTE{attributes}]{text}[/QUOTE]','={name};{post}');
//*/
?>

TrioxX
Was soll ich sagen... Wie immer perfekt! Mich wundert ja, dass du noch nicht ausgerastet bist, während du versucht hast, mir zu helfen großes Grinsen

Ich bin im Laufe des Tages hier echt am Stock gegangen und bin echt froh, dass das nun auch geschafft ist fröhlich

Im Übrigen habe ich eine 3. Variante gefunden:

code:
1:
[quote name=§#39;Tester§#39; date=§#39;10 March 2010 - 08:13 PM§#39; timestamp=§#39;1268251994§#39; post=§#39;23413§#39;]


Das & habe ich zur korrekten Darstellung mal durch § ersetzt Augenzwinkern

Deswegen mache ich es nun so:

php:
1:
2:
3:
4:
<?
$text str_replace("§#39;""'"$text);
return $this->modify($text,'quote','\[;\]','[QUOTE{attributes}]{text}[/QUOTE]','={name};{post}');
?>


Wer auch immer sich sowas ausdenkt... Er gehört erschossen!

Dir auf jeden Fall mal wieder tausend Dank! Du hast mir den Tag gerettet!!!
moonsword
hab die funkntion nochmal überdacht und nochmal etwas geändert...jetzt sollte sie bei größeren datenmengen schneller laufen, weil nur 1 regex eingesetzt wird...man könnte das nochmal überdenken mit dem ersetzen und 2 große arrays schaffen, die man dann ersetzt, statt einem ständigen str_replace aufruf, aber weiß nicht, wie performant das ist smile

jetzt werden die attribute nichtmehr mit einem regex ausgesondert, sondern einfah über 2 explodes getrennt...das eine schafft ein array, durch das ich mit einem map durchgeh...pro attribute wird es nochmal getrennt und dann zurückgegeben, ohne die anführungszeichen und schon vorbereitet zum ersetzen smile array_map ist doch echt was schönes und mächtiges....nur die lambda funktion finde ich in python schöner ^^
php:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
<?php function modify($str,$tag,$delimiter,$tmp,$attr) {
    list($d_left,$d_right) = explode(';',$delimiter);

    preg_match_all('/'.$d_left.$tag.'(.*?)'.$d_right.'(.*?)'.$d_left.'\/'.$tag.$d_right.'/is',$str,$match);

    for($i 0$i count($match[0]); $i++) {

        if(!empty($match[1][$i])) {
            $attributes array_map(create_function(
                '$e',
                '$a = explode("=",$e);return array("{".$a[0]."}",str_replace(array("\'","\""),"",$a[1]));'
            ),explode(' ',trim($match[1][$i])));

            foreach($attributes as $a) {
                $attr str_replace($a[0],$a[1],$attr);
            }
        } else $attr '';
        $str str_replace($match[0][$i],str_replace(array('{attributes}','{text}'),array($attr,$match[2][$i]),$tmp),$str);
    }
    return $str;
} ?>


edit2:
die beiden schleifen haben mich genervt...im prinzip 2mal durchgehen ist zeitverschwendung....deshalb ist hier noch eine verbesserte version für die attribute...zwar keine map funktion (hab ewig gesucht, aber finde keine möglichkeit wie in perl auf den key zuzugreifen) und mit einer foreach...aber es geht und sollte schneller sein
php:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
<?php function modify($str,$tag,$delimiter,$tmp,$attr) {
    list($d_left,$d_right) = explode(';',$delimiter);

    preg_match_all('/'.$d_left.$tag.'(.*?)'.$d_right.'(.*?)'.$d_left.'\/'.$tag.$d_right.'/is',$str,$match);

    for($i 0$i count($match[0]); $i++) {
        if(!empty($match[1][$i])) {
            foreach(explode(' ',trim($match[1][$i])) as $att) {
                $a explode('=',$att);
                $attr str_replace('{'.$a[0].'}',str_replace(array('"','\''),'',$a[1]),$attr);
            }
        } else $attr '';
        $str str_replace($match[0][$i],str_replace(array('{attributes}','{text}'),array($attr,$match[2][$i]),$tmp),$str);

    }
    return $str;
} ?>


wieso? ich finde sowas zu verwenden echt sinvoll...deshalb gehört er nicht erschossen smile und warum sollte ich ausrasten, du hast immer nette kleine codeschnipsel probleme...die machen spass zu lösen ^^ und wie du merkst, geht es nicht darum eine lösung zu finden, sondern die schönste lösung zu finden smile und die schönste wäre eindeutig ein einzeiler, aber regex lässt das nicht zu ^^
TrioxX
Das mit dem Erschiessen war auf die verschiedenen Versionen des Quote-Tags bezogen Augenzwinkern

Jedenfalls hat unser kleines Intermezzo hier mein Problem zu meiner vollsten Zufriedenheit gelöst smile

Danke dir noch einmal.

Bis zum nächsten "Codeschnipsel"-Problem großes Grinsen
(hier klicken, um zum Original Thread zu gelangen)



Tipp: Ranking-Konzept.de - Das SEO-Forum (Forum rund um die Suchmaschinenoptimierung) der artaxo AG.
Das große Versicherungs ABC von Versicherung.de - mit allen Aspekten der Computerversicherungen!
Fan-Foren.de, die große Community mit Musikforum ist ab sofort online.