RegEx: String A im String B ersetzen mit modifiziertem String A

N0ACE

Mitglied
Hallo liebe Community,

ich habe folgende Situation: Ein String:
Code:
Das Modell AB0FF2DE23 ist in Reparatur

Dabei soll das Modell ("AB0FF2D23") umgewandelt werden. Die Modell-Nr. besteht immer aus drei Blöcken, welche unterschiedlich aufgebaut sein können.

Ziel ist es, den String so umzuwandeln, dass er wie folgt erscheint:
Code:
Das Modell AB0 FF2 DE23 ist in Reparatur

Das RegEx-Pattern, welches das Modell ("AB0FF2D23") herausfiltert ist vorhanden (die drei Blöcke können unterschiedlich aufgebaut sein):
Code:
([A-Z]{2}\d|\d{3})([A-Z]{2}\d{1,2}|\d{3}|[A-Z]{3})(_)?([A-Z]\d{3}|[A-Z]{1,3}\d{2}|[A-Z]{3}\d|[A-Z]{4}|\d{3})(_2)?

Wie erreiche ich es, dass o.g. Satz so umgewandelt wird, dass zwischen den drei Blöcken je ein Leerzeichen eingesetzt wird ("AB0 FF2 DE23") und damit das orig. Modell ersetze?


Vielen Dank für Eure Hilfe und weiterhin einen schönen Tag!!

Nachtrag:

Ich arbeite in PHP und meine bisherigen Ansätze beziehen sich auf eine Kombination von preg_match() um die Modell-Nr. herauzufiltern und via implode() "schön" zu machen und diese dann via preg_replace() im Ursprungs-String zu ersetzen.

Gibt es hier eine elegantere, performantere Möglichkeit?
 

deepthroat

Erfahrenes Mitglied
Hi.

Was soll den mit den _ und _2 Teilen passieren?

Grundsätzlich kannst du natürlich versuchen mit einem preg_replace auszukommen, falls du die _ und _2 weglassen willst?

PHP:
preg_replace('/([A-Z]{2}\d|\d{3})([A-Z]{2}\d{1,2}|\d{3}|[A-Z]{3})(_)?([A-Z]\d{3}|[A-Z]{1,3}\d{2}|[A-Z]{3}\d|[A-Z]{4}|\d{3})(_2)?/', '\1 \2 \4', $text);
Test: http://www.myregextester.com/?r=de2e1e69
 

N0ACE

Mitglied
Der "_" zwischen Block 2 und 3 und das "_2" am Ende sind optional und tauchen (leiden) in manchen Modell-Nr. auf und sind daher notwendig. Sollte eines der beiden gefunden werden, soll da aber KEINE Leerzeichen zwischen.

Bsp:
Code:
AB0FF2_DE23_2

Soll zu:
Code:
 AB0 FF2_DE23_2

Ist ein wenig fickerig, aber leider Voraussetzung ...


Danke für die Hilfe!

Dein Ansatz gefällt mir sehr gut! Wie gesagt, sind "_" und "_2" notwendig.

Gibt es eine Möglichkeit, das Leerzeichen zwischen Block 2 und 3 nur dann zu setzen, wenn KEIN "_" gefunden wurde?

Hier mein Bsp.: http://www.myregextester.com/?r=2fac15c6
 

Yaslaw

alter Rempler
Moderator
Alle Nummern finden die nicht an eine Zahl oder einen Buchstaben grenzen (dank den Assertions am Anfang und am Ende des Pattern)

Code:
== Findet Die Nummer ==
Das Modell AB0FF2DE23 ist in Reparatur
Das Modell AB0FF2DE23
Das Modell AB0FF2DE23.
Das Modell "AB0FF2DE23"
Das Modell (AB0_FF2 DE23)

==Findet Nicht
Das ModellAB0FF2DE23
Das Modell AB0FF2DE23123

PHP:
$pattern = '/(?<![[:alnum:]])([[:alpha:]]{2}\d)[ ]?([[:alpha:]]{2}\d)[ ]?([[:alpha:]]{2}\d{2})(?![[:alnum:]])/';
$replace = '\1 \2 \3'; 
$result = preg_replace($pattern, $replace, $subject);

Und falls es anstelle von Leerzeichen _ haben kann
PHP:
$pattern = '/(?<![[:alnum:]])([[:alpha:]]{2}\d)[ _]?([[:alpha:]]{2}\d)[ _]?([[:alpha:]]{2}\d{2})(?![[:alnum:]])/';
 

deepthroat

Erfahrenes Mitglied
Der "_" zwischen Block 2 und 3 und das "_2" am Ende sind optional und tauchen (leiden) in manchen Modell-Nr. auf und sind daher notwendig. Sollte eines der beiden gefunden werden, soll da aber KEINE Leerzeichen zwischen.

Bsp:
Code:
AB0FF2_DE23_2

Soll zu:
Code:
 AB0 FF2_DE23_2

Gibt es eine Möglichkeit, das Leerzeichen zwischen Block 2 und 3 nur dann zu setzen, wenn KEIN "_" gefunden wurde?
Nein, das geht lieder nicht mit preg_replace. Den zweiten Fall kann man noch als Spezialfall behandeln indem man das _2 einfach in die Gruppe hineinzieht:
Code:
([A-Z]{2}\d|\d{3})([A-Z]{2}\d{1,2}|\d{3}|[A-Z]{3})(_?)((:?[A-Z]\d{3}|[A-Z]{1,3}\d{2}|[A-Z]{3}\d|[A-Z]{4}|\d{3})(:?_2)?)
Aber beim _ funktioniert das Leider nicht. Du kannst stattdessen preg_replace_callback Funktion verwenden oder mußt mehrfach ersetzen: 1. Fall ohne _ und mit Leerzeichen, 2. Fall mit _ und ohne Leerzeichen.

PHP:
function format_model($matches) {
  $delim = ($matches[3]) ? $matches[3] : ' ';

  return $matches[1] . ' ' . $matches[2] . $delim . $matches[4];
}

preg_replace_callback('/([A-Z]{2}\d|\d{3})([A-Z]{2}\d{1,2}|\d{3}|[A-Z]{3})(_?)((:?[A-Z]\d{3}|[A-Z]{1,3}\d{2}|[A-Z]{3}\d|[A-Z]{4}|\d{3})(:?_2)?)/'',
  'format_model',
  '...');
(ungetestet)
 
Zuletzt bearbeitet: