Discussion:
Ist hier noch jemand? str_replace multiple replacement
(zu alt für eine Antwort)
Detlef Paschke
2024-11-04 17:23:47 UTC
Permalink
Hallo an alle,

ist sehr ruhig geworden. Ich hoffe mal, dass hier noch jemand ließt.

Ich habe in einem Script eine Zeile, die zwei mal str_replace ausführt,
weil ich zu dumm bin, das in einem mal hinzubekommen.

str_replace(['../', './'], '', str_replace('\\', '/', $datei));

Mit preg_replace geht es so, wie ich es mir vorstelle, doch so kann ich
es kaum noch lesen.

preg_replace(['/(\.\/|\.\.\/)/', '/(\\\\)/'], ['', '/'], $datei);

Ich bekomme ein ODER im Suchausdruck mit str_replace einfach nicht hin
oder zumindest nicht so, dass ein Array im Ersetzen-Teil dann noch
zuverlässig funktioniert.
So funktioniert es zwar, aber schön ist das auch nicht.

str_replace(['./', '../', '\\'], ['','','/'], $datei)

Ist noch einer von den Profis hier, die genau wissen, wo wieder mal eine
Klammer fehlt oder das Hochkomma falsch ist?

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblick" gibt es nur auf:
https://schabau.eu

Meine "Merkzettel" findet man unter:
https://helpdesk.schabau.eu
Stefan+ (Stefan Froehlich)
2024-11-04 22:56:49 UTC
Permalink
[Funktioniert, braucht aber 2 Aufrufe]
str_replace(['../', './'], '', str_replace('\\', '/', $datei));
[Funktioniert nicht]
str_replace(['./', '../', '\\'], ['','','/'], $datei)
Mich würde ja interessieren, wie Du vom einen zum anderen Ausdruck
gekommen bist - unmittelbar einsichtig ist das nämlich nicht :-)

An sich wären die beiden Schreibweisen (nahezu) ident: Wenn Du ein
Array übergibst, werden die Elemente einfach der Reihe nach
durchiteriert. Die "funktionierende" Variante sollte also kaum
teurer sein.

Aber natürlich geht es auch in der eleganteren Version, Du musst nur
aus hoffentlich naheliegenden Gründen sicherstellen, dass ../ *vor
./ ersetzt wird.
Mit preg_replace geht es so, wie ich es mir vorstelle, doch so
kann ich es kaum noch lesen.
preg_replace(['/(\.\/|\.\.\/)/', '/(\\\\)/'], ['', '/'], $datei);
Hier funktioniert es unabhängig von der Reihenfolge, da reguläre
Ausdrücke immer den längsten Match suchen. Die Auswahl zwischen .
und .. ließe sich allerdings auch einfacher treffen, die Klammern um
das Pattern sind unnötig, und für den Delimiter empfiehlt sich in
diesem Fall ein anderes Zeichen. Ich würde etwas lesbarer schreiben:

preg_replace(['#\.\.?/#', '#\\\\#'], ['', '/'], $datei);

Servus,
Stefan
--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike

Stefan - Wahnsinn, der begeistert!
(Sloganizer)
Detlef Paschke
2024-11-05 09:03:00 UTC
Permalink
Post by Stefan+ (Stefan Froehlich)
[Funktioniert, braucht aber 2 Aufrufe]
str_replace(['../', './'], '', str_replace('\\', '/', $datei));
[Funktioniert nicht]
str_replace(['./', '../', '\\'], ['','','/'], $datei)
...
Aber natürlich geht es auch in der eleganteren Version, Du musst nur
aus hoffentlich naheliegenden Gründen sicherstellen, dass ../ *vor
./ ersetzt wird.
Stimmt danke, im eigentlichen Script ist es auch richtig herum, in der
"Test.php" habe ich es korrigiert. Da war mir der Fehler noch gar nicht
aufgefallen.
Post by Stefan+ (Stefan Froehlich)
Mit preg_replace geht es so, wie ich es mir vorstelle, doch so
kann ich es kaum noch lesen.
preg_replace(['/(\.\/|\.\.\/)/', '/(\\\\)/'], ['', '/'], $datei);
Hier funktioniert es unabhängig von der Reihenfolge, da reguläre
Ausdrücke immer den längsten Match suchen. Die Auswahl zwischen .
und .. ließe sich allerdings auch einfacher treffen, die Klammern um
das Pattern sind unnötig, und für den Delimiter empfiehlt sich in
preg_replace(['#\.\.?/#', '#\\\\#'], ['', '/'], $datei);
Mein Beweggrund ist, was bis jetzt nur mit diesen blöden regulären
Ausdrücke und preg_replace funktioniert, mit str_replace hinzubekommen.
Es funktioniert ja auch ganz schick mit den preg_replace Varianten, aber
es ist so fürchterlich zu lesen für mich.

Ganz primitiv übersetzt:

Array1('../' ODER './', '\'), Array2('', '/')

Und genau diesen ODER Teil, dass ../ ODER ./ zu '' wird, also gelöscht
werden sollen, bekomme ich mit str_replace nicht hin. Und das in so
einem hübschen kleinen Einzeiler. :-)
Post by Stefan+ (Stefan Froehlich)
Servus,
Stefan
Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblick" gibt es nur auf:
https://schabau.eu

Meine "Merkzettel" findet man unter:
https://helpdesk.schabau.eu
Stefan+ (Stefan Froehlich)
2024-11-05 09:59:35 UTC
Permalink
Post by Detlef Paschke
Post by Stefan+ (Stefan Froehlich)
Post by Detlef Paschke
preg_replace(['/(\.\/|\.\.\/)/', '/(\\\\)/'], ['', '/'], $datei);
Hier funktioniert es unabhängig von der Reihenfolge, da reguläre
Ausdrücke immer den längsten Match suchen. Die Auswahl zwischen .
und .. ließe sich allerdings auch einfacher treffen, die Klammern um
das Pattern sind unnötig, und für den Delimiter empfiehlt sich in
preg_replace(['#\.\.?/#', '#\\\\#'], ['', '/'], $datei);
Mein Beweggrund ist, was bis jetzt nur mit diesen blöden regulären
Ausdrücke und preg_replace funktioniert, mit str_replace
hinzubekommen.
Es dürfte durchaus sinnvoll sein, reguläre Ausdrücke nur dort zu
verwenden, wo sie auch erforderlich sind. Trotzdem schadet es nicht,
sie lesbar zu formulieren :)
Post by Detlef Paschke
Array1('../' ODER './', '\'), Array2('', '/')
Und genau diesen ODER Teil, dass ../ ODER ./ zu '' wird, also
gelöscht werden sollen, bekomme ich mit str_replace nicht hin. Und
das in so einem hübschen kleinen Einzeiler. :-)
Wieso? Inzwischen sollte das ja klappen.

Du musst Dir halt vergegenwärtigen, dass Deine Oder-Verknüpfung
einen logischen Fehler enthält: Jeder String, der '../' enthält,
enthält automatisch auch './', und sobald Du letzteres durch den
Leerstring ersetzt, bleibt Dir ein unerwünschter Punkt übrig.

Löse Dich von der Oder-Verknüpfung und ersetze gedanklich einen
Teilstring nach dem anderen, immer mit dem längsten beginnend.

Servus,
Stefan
--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike

Stefan - die vollkommenste Nuance von selig!
(Sloganizer)
Detlef Paschke
2024-11-05 11:38:32 UTC
Permalink
Post by Stefan+ (Stefan Froehlich)
Post by Detlef Paschke
Array1('../' ODER './', '\'), Array2('', '/')
Und genau diesen ODER Teil, dass ../ ODER ./ zu '' wird, also
gelöscht werden sollen, bekomme ich mit str_replace nicht hin. Und
das in so einem hübschen kleinen Einzeiler. :-)
Wieso? Inzwischen sollte das ja klappen.
In keiner Weise. Mit preg_replace funktioniert es wie ich es mir
vorstelle, ist aber schwerer zu lesen. Mit str_replace geht es nur
nacheinander oder wenn das replace Arrays und das search Array die selbe
Anzahl an Werten haben.

$datei = './folder\file.txt ODER ../folder\file.txt';

echo '<p>str_replace (./folder\file.txt ODER ../folder\file.txt)</p>';
var_dump(str_replace(['../', './'], '', str_replace('\\', '/', $datei)));

Die ursprüngliche, derzeit verwendete und funktionierende Variante. Die
wollte ich gern in ein str_replace "zusammenschieben".

var_dump(str_replace(['../', './', '\\'], ['', '', '/'], $datei));

Die Variante funktioniert, aber es sind im search und replace Array die
selbe Anzahl von Werten. Die Werte '../' und './' haben den gleichen
replace Wert. Ich hätte ja gern, dass sie den selben haben.

echo '<p>str_replace WUNSCH';
var_dump(str_replace([('../' | './'), '\\'], ['', '/'], $datei));

Meine Wunschvorstellung mit ODER Verknüpfung für den ersten Wert im
search Array, die beide auf den ersten Wert des replace Array zutreffen
sollen. Funktioniert nur für den zweiten Teil. Nur \ wird gegen /
ausgetauscht.

echo '<p>preg_replace (./folder\file.txt ODER ../folder\file.txt)</p>';
var_dump(preg_replace(['/(\.\/|\.\.\/)/', '/(\\\\)/'], ['', '/'], $datei));
var_dump(preg_replace(['#\.\.?/#', '#\\\\#'], ['', '/'], $datei));
var_dump(preg_replace(['#\.+/#', '#\\\\#'], ['', '/'], $datei));

Die Varianten mit preg_replace, die alle funktionieren. Meine erste
Variante mit ODER, dein Vorschlag und ein von mir daraufhin
abgeleiteter, der wohl auch bei .....\ greifen würde, was hier aber
keine Rolle spielt.
Post by Stefan+ (Stefan Froehlich)
Du musst Dir halt vergegenwärtigen, dass Deine Oder-Verknüpfung
einen logischen Fehler enthält: Jeder String, der '../' enthält,
enthält automatisch auch './', und sobald Du letzteres durch den
Leerstring ersetzt, bleibt Dir ein unerwünschter Punkt übrig.
Das ist ja nun behoben und betraf auch nur meine bastel Datei.
Post by Stefan+ (Stefan Froehlich)
Löse Dich von der Oder-Verknüpfung und ersetze gedanklich einen
Teilstring nach dem anderen, immer mit dem längsten beginnend.
Ganz gebe ich noch nicht auf, manchmal muss man nur das richtige
Suchwort bei google haben und findet was man schon ewig sucht. :-)
Post by Stefan+ (Stefan Froehlich)
Servus,
Stefan
Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblick" gibt es nur auf:
https://schabau.eu

Meine "Merkzettel" findet man unter:
https://helpdesk.schabau.eu
Detlef Paschke
2024-11-05 11:55:13 UTC
Permalink
Post by Detlef Paschke
$datei = './folder\file.txt ODER ../folder\file.txt';
...
echo '<p>preg_replace (./folder\file.txt ODER ../folder\file.txt)</p>';
...
var_dump(preg_replace(['#\.+/#', '#\\\\#'], ['', '/'], $datei));
Und für den \ reicht für meinen Zweck wohl auch '#\\\#' mit nur drei \.
Das ist dieser Nerv mit den regulären Ausdrücken und dem ewigen escapen.

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblick" gibt es nur auf:
https://schabau.eu

Meine "Merkzettel" findet man unter:
https://helpdesk.schabau.eu
Stefan+ (Stefan Froehlich)
2024-11-05 12:19:45 UTC
Permalink
Post by Detlef Paschke
Post by Stefan+ (Stefan Froehlich)
Post by Detlef Paschke
Array1('../' ODER './', '\'), Array2('', '/')
Und genau diesen ODER Teil, dass ../ ODER ./ zu '' wird, also
gelöscht werden sollen, bekomme ich mit str_replace nicht hin.
Und das in so einem hübschen kleinen Einzeiler. :-)
Wieso? Inzwischen sollte das ja klappen.
In keiner Weise. Mit preg_replace funktioniert es wie ich es mir
vorstelle, ist aber schwerer zu lesen. Mit str_replace geht es nur
nacheinander oder wenn das replace Arrays und das search Array die
selbe Anzahl an Werten haben.
$datei = './folder\file.txt ODER ../folder\file.txt';
echo '<p>str_replace (./folder\file.txt ODER ../folder\file.txt)</p>';
var_dump(str_replace(['../', './'], '', str_replace('\\', '/', $datei)));
Die ursprüngliche, derzeit verwendete und funktionierende Variante. Die
wollte ich gern in ein str_replace "zusammenschieben".
var_dump(str_replace(['../', './', '\\'], ['', '', '/'], $datei));
Eben, passt. Fertig und aus :)
Post by Detlef Paschke
Die Werte '../' und './' haben den gleichen replace Wert. Ich
hätte ja gern, dass sie den selben haben.
echo '<p>str_replace WUNSCH';
var_dump(str_replace([('../' | './'), '\\'], ['', '/'], $datei));
Sorry, wenn ich Deinen WUNSCH zerstöre, aber wie sollte das denn
funktionieren? Einmal abseits der PHP-Spezifikation, rein
wunschtheoretisch: ('../' | './') ist wahlweise Unfung, weil sich
Strings nicht verodern lassen, oder Unfung, weil das Ergebnis der
(egal ob typkonvertierten oder bitweisen) Veroderung nicht das ist,
was Du gerne hättest. Jedenfalls aber kannst Du nicht einer
Funktion, die als Argument einen String erwartet (und sei es in der
Komponente eines Arrays) statt dessen eine Liste von Strings (oder
einen arithmetischen Ausdruck) geben, in der Hoffnung, dass daraus
auf magische Weise das richtige entsteht.

Entweder Du machst ein 1:1 Mapping von search und replace (was ich
hier bevorzugen würde), oder Du nimmst eben einen regulären
Ausdruck, in dem Alternativen per Definition enthalten sind. Dann
landest Du halt wieder bei preg_replace().
Post by Detlef Paschke
Post by Stefan+ (Stefan Froehlich)
Löse Dich von der Oder-Verknüpfung und ersetze gedanklich einen
Teilstring nach dem anderen, immer mit dem längsten beginnend.
Ganz gebe ich noch nicht auf, manchmal muss man nur das richtige
Suchwort bei google haben und findet was man schon ewig sucht. :-)
Nicht, wenn bereits die Grundidee einen Logikfehler enthält.

Servus,
Stefan
--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike

Stefan - Eine Klasse für sich.
(Sloganizer)
Detlef Paschke
2024-11-05 14:27:13 UTC
Permalink
Post by Stefan+ (Stefan Froehlich)
Entweder Du machst ein 1:1 Mapping von search und replace (was ich
hier bevorzugen würde), oder Du nimmst eben einen regulären
Ausdruck, in dem Alternativen per Definition enthalten sind. Dann
landest Du halt wieder bei preg_replace().
Ich habe so meine Probleme mit regulären Ausdrücken (da werde ich sicher
nicht der einzige sein) und dann insbesondere damit, wie preg_replace()
damit umgeht.

Ich habe es ja z.B. so Begriffen, dass mit \ das nachverfolgende Zeichen
gequotet wird. Ich muss also \\ eingeben, um ein \ zu bekommen. Bei
str_replace() ist das auch so und bei allen möglichen anderen Zeichen
klappt das auch mit preg_replace() so. Wieso brauche ich bei
preg_replace() aber \\\ um ein \ zu bekommen??? Das ist für mich einfach
unbegreiflich.

Die beiden Varianten sind gerade in meiner näheren Auswahl und noch
halbwegs lesbar.

var_dump(preg_replace(['/(\.+\/)/', '/(\\\)/'], ['', '/'], $datei));
var_dump(preg_replace(['#\.+/#', '#\\\#'], ['', '/'], $datei));

Was sagen die Rauten aus deinem Beispiel gegenüber der runden Klammern
eigentlich genau aus?

Ich kann nichts zu den Rauten finden und sonst wird nur die Variante mit
den runden Klammern gezeigt. Meine erste Anlaufstelle ist eigentlich
immer php.net und da finde ich gar keine Variante mit Rauten.
Post by Stefan+ (Stefan Froehlich)
Servus,
Stefan
Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblick" gibt es nur auf:
https://schabau.eu

Meine "Merkzettel" findet man unter:
https://helpdesk.schabau.eu
Arno Welzel
2024-11-07 16:31:33 UTC
Permalink
Detlef Paschke, 2024-11-04 18:23:


[...]
Post by Detlef Paschke
So funktioniert es zwar, aber schön ist das auch nicht.
str_replace(['./', '../', '\\'], ['','','/'], $datei)
Was ist daran "nicht schön?".
--
Arno Welzel
https://arnowelzel.de
Detlef Paschke
2024-11-08 10:25:49 UTC
Permalink
Post by Arno Welzel
[...]
Post by Detlef Paschke
So funktioniert es zwar, aber schön ist das auch nicht.
str_replace(['./', '../', '\\'], ['','','/'], $datei)
Was ist daran "nicht schön?".
Schöner fände ich das Ersetzungs-Array so, ['','/'] wie es bei
preg_replace in allen Varianten geht. In einer Variante eben auch mit
logischen ODER Operator, ['/(\.\/|\.\.\/)/', '/(\\\\)/'] und ich hoffte,
dass sich das auf str_replace übertragen lässt. Dem ist aber wohl nicht so.

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblick" gibt es nur auf:
https://schabau.eu

Meine "Merkzettel" findet man unter:
https://helpdesk.schabau.eu
Arno Welzel
2024-11-08 16:29:11 UTC
Permalink
Post by Detlef Paschke
Post by Arno Welzel
[...]
Post by Detlef Paschke
So funktioniert es zwar, aber schön ist das auch nicht.
str_replace(['./', '../', '\\'], ['','','/'], $datei)
Was ist daran "nicht schön?".
Schöner fände ich das Ersetzungs-Array so, ['','/'] wie es bei
preg_replace in allen Varianten geht. In einer Variante eben auch mit
Nein, preg_replace() arbeitet auch nicht so.

Zitat aus <https://www.php.net/manual/en/function.preg-replace.php>:

If there are fewer elements in the replacement array than in the pattern
array, any extra patterns will be replaced by an empty string.

(Zitat Ende)

Das wäre dann für ['', '/'] als replacement:

'./' --> '';
'../' --> '/';
'\\' --> '';

Denn ab dem 3. Suchmuster wird nur '' als Ersetzung verwendet.
Post by Detlef Paschke
logischen ODER Operator, ['/(\.\/|\.\.\/)/', '/(\\\\)/'] und ich hoffte,
dass sich das auf str_replace übertragen lässt. Dem ist aber wohl nicht so.
Nein, genau deswegen gibt es ja preg_replace(), weil das "oder" halt ein
Teil des regulären Ausdrucks wäre.
--
Arno Welzel
https://arnowelzel.de
Loading...