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

#1
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
#2
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
 
#3
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

n/a
Moderator
#4
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
#5
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: