RegEx-Horror

Lil-rich

Erfahrenes Mitglied
Mir schwirrt schon total der Schädel von meinem RegEx-Pattern... Irgendwie stehe ich auf dem Schlauch und bräuchte eine kleine Hilfe.

Folgendes Skript:
PHP:
<?php

$string = "Bognerstraße 29";
$string = "Bognerstraße 29";
$string = "Bognerstraße 29 RH";
$string = "Bognerstraße 29 RH 3.OG";
$string = "Bognerstraße 29 3.OG";
$string = "Bognerstraße 29 3.OG RH";
$string = "Bognerstraße 29 RH";
$string = "Bognerstraße 29 3OG";
$string = "Bognerstraße 29a";
$string = "Bognerstraße 29 a";
$string = "Bognerstraße 29 a RH";
$string = "Bognerstraße 29 a RH 3.OG";
$string = "Bognerstraße 29 a 3.OG";
$string = "Bognerstraße 29 a 3.OG RH";
$string = "Bognerstraße 29 aRH";
$string = "Bognerstraße 29 a3OG";
$string = "Bognerstraße 29a RH";
$string = "Bognerstraße 29a RH 3.OG";
$string = "Bognerstraße 29a 3.OG";
$string = "Bognerstraße 29a 3.OG RH";
$string = "Bognerstraße 29aRH";
$string = "Bognerstraße 29a3OG";

// altes Pattern (hatte Probleme beim Splitten z.B. von "[...]straße 29 RH")
$pattern = '/[a-zA-ZäöüÄÖÜß\s]+ [0-9]+[\s]*[a-zA-Z]?[\s]*/is';

// neues Pattern - funktioniert leider nicht wie erwünscht
$pattern = '/[a-zA-ZäöüÄÖÜß\s]+[0-9]*[\s]*([a-zA-Z]?[\s]+)|[\s]*/is';

$result = preg_split($pattern, $string);

echo print_r($result);

?>

Ausgabe soll sein:
Code:
(je nach vorhandenen Angaben im $string)
$result[0] => "Bognerstraße 29a"
bzw.
$result[0] => "Bognerstraße 29 a"
bzw.
$result[0] => "Bognerstraße 29"
bzw.
$result[0] => "Bognerstraße"

sowie
$result[1] => "[Rest]"

Im Prinzip ist es von der Logik her gar nicht soo schwer:
Code:
1.) Beliebige Zeichenkombination (ohne Zahlen) ([a-zA-ZäöüÄÖÜß\s]+)
2.) Beliebige Anzahl von Zahlen ([0-9]*)
3.) Beliebige Anzahl von Whitespaces ([\s]*)

4.) Genau ein Buchstabe(n) und beliebige Anzahl von Whitespaces, aber kein weiterer Buchstabe
ODER: kein Buchstabe und beliebige Anzahl von Whitespaces

5.) Beliebige Zeichenkombination >= 1 ([a-zA-ZäöüÄÖÜß0-9\s]*)

Wie man sehen kann, habe ich bei Nummer 4 mein eigentliches Problem. Ich weiß nicht genau, wie ich mit dem Pipezeichen arbeiten kann. Theroretisch ja einfach meine "Expression" einklammern und, wie im Code eben auch, "pipen". Aber irgendwie zerhaut es mir dann alles?

Wahrscheinlich habe ich irgendwo nen grundlegenden Denkfehler. Ich arbeite so selten mit Regular Expressions...

Bin für alle Hilfen dankbar, sitze jetzt schon ne Weile vor allen möglich Live-RegEx-Testern und Hilfe-Seiten, aber ich komme nicht drauf^^
 
Also es gibt einige Punkte, die mir bei Dir aufgefallen sind, die man verbessern könnte. Beispielsweise sollte das \s nicht in eine Zeichenmenge geschrieben werden.
PHP:
$pattern = '/[a-zA-ZäöüÄÖÜß\s]+ [0-9]*\s*[a-zA-Z]?\s*/is';
 
Danke für den Hinweis! Ist ja immer gut, wenn man sowas auch gesagt bekommt :)
Das eigentliche Problem hat es aber noch nicht gelöst.

Hab auch nochmal hier im Forum recherchiert und bin auf dieses Thema gestoßen:
https://www.tutorials.de/threads/adresse-und-hausnummer-mit-regular-expression.394488/

Leider keine abschließende Lösung...
Ich werde man sehen, ob ich statt mit RegEx nicht doch über explode alles zerlege und prüfe - ich denke da kann man auch Sonderfälle leichter beachten. Wird zwar Spaghetti-Code und alles andere als schön, aber mir scheint so, als wäre das "in RegEx" ein wenig zu komplex zu lösen.
 
Du könntest mal folgendes für uns/mich machen: schreibe einfach in einer Spalte auf, was Du als Eingabewert hast, und in der Spalte daneben, was Du als Ergebnis erwartest. Denn ich verstehe anscheinend nicht ganz, wo bei Dir das Problem ist, da es bei mir fehlerfrei funktioniert – zumindest erhalte ich das, was ich erwarte.
 
Was ich bekomme -> was ich hinterher will (Formatierung will leider nicht so wie ich will)
Code:
Weiherweg 6a 9. OG            -> $street = "Weiherweg 6a", $streetAd = "9. OG"
Felberstraße 7                -> $street = "Felberstraße 7", $streetAd = ""
Dr.-Mack-Straße 101            -> $street = "Dr.-Mack-Straße 101", $streetAd = ""
Ziegelstraße 18                -> $street = "Ziegelstraße 18", $streetAd = ""
Äußere Uferstraße            -> $street = "Äußere Uferstraße", $streetAd = ""
Äußere Uferstraße 76 B OG        -> $street = "Äußere Uferstraße 76b", $streetAd = "OG"
Trettachstraße 12 5.OG            -> $street = "Trettachstraße 12", $streetAd = ""
Kantstraße 11                -> $street = "Kantstraße 11", $streetAd = ""
Buchenstraße 27 b            -> $street = "Buchenstraße 27b", $streetAd = "8. OG"
Landrat-Dr.-Frey-Pla 5 a 8. OG        -> $street = "Landrat-Dr.-Frey-Pla 5a", $streetAd = ""
Gögginger Straße 13            -> $street = "Gögginger Straße 13", $streetAd = ""
Königsbrunner Straße 33a        -> $street = "WKönigsbrunner Straße 33a", $streetAd = ""
Hochfeldstraße10            -> $street = "Hochfeldstraße 10", $streetAd = ""
Vogelmauer 78 a OG 2            -> $street = "Vogelmauer 78a", $streetAd = "OG 2"
Pfarrer-Bogner-Straß 16 1. OG        -> $street = "Pfarrer-Bogner-Straß 16", $streetAd = "1. OG"
Provinostraße 1 9 St.            -> $street = "Provinostraße 1", $streetAd = "9 St."
Curtiusstraße 2 1. OG            -> $street = "Curtiusstraße 2", $streetAd = "1. OG"
Haßlerstraße 1 RH            -> $street = "Haßlerstraße 1", $streetAd = "RH"
Waterloostraße 6 EG            -> $street = "Waterloostraße 6", $streetAd = "EG"
Langemarckstraße 3OG            -> $street = "Langemarckstraße", $streetAd = "3OG"

Habe es jetzt mal in PHP so umgesetzt:
PHP:
$input = "Weiherweg 6a 9. OG";

$i = 0;
$step = 0;
while(isset($input[$i]))
{
   if (DEBUG) echo "<br>splitTelegram Street [".__CLASS__."]: [".$input[$i]."]";
   
   if (preg_match('/[a-zA-Z\x{00E4}\x{00F6}\x{00FC}\x{00C4}\x{00D6}\x{00DC}\x{00df}\s\-.]/', $input[$i]) && ($step == 0 || $step == 1))
   {
     if ($step == 0)
     {
       if (preg_match('/[\s]/', $input[$i]))
       {
         $street .= " ";
       }
     
       $street .= trim($input[$i]);
       if (DEBUG) echo "<br>splitTelegram Street0 [".__CLASS__."]: [".$street."]";
     } else if ($step == 1)
     {
       if (!isset($input[$i+2]) || preg_match('/[\s]/', $input[$i+2]))
       {
         $street .= trim($input[$i]);
         $i++;
         $street .= trim($input[$i]);
         $step = 2;
       } else
       {
         $street .= trim($input[$i]);
         $step = 2;
       }
     }
   } else if (is_numeric($input[$i]) && ($step == 0 || $step == 1))
   {
     if ($step == 0)
     {
       $street = trim($street)." ".trim($input[$i]);
       $step = 1;
     } else
     {
       $street .= trim($input[$i]);
     }
   } else
   {
     $streetAd .= $input[$i];
   }
   
   $i++;
}

if (DEBUG) $streetAd .= " (".$input.")";
 
PHP:
function match_address( $value ) {
  static $pattern = '/^([a-zÄÖÜäöüß .-]+)(?:[ ]+([0-9]*[ ]*[a-z]?)(?:[ ]+([a-z0-9. ]+))?)?$/is';
  
  if ( preg_match( $pattern, $value, $matches ) !== 1 ) {
    return;
  }

  if ( !isset( $matches[ 2 ] ) ) {
    $matches[ 2 ] = null;
  } else {
    $matches[ 2 ] = strtolower( str_replace( ' ', '', $matches[ 2 ] ) );
  }

  if ( !isset( $matches[ 3 ] ) ) {
    $matches[ 3 ] = null;
  }

  return array(
    'street'   => $matches[ 1 ],
    'number'   => $matches[ 2 ],
    'addition' => $matches[ 3 ]
  );
}

print_r( match_address( 'Äußere Uferstraße 76 B OG' ) );
# Ausgabe:
#
# Array
# (
#   [street] => Äußere Uferstraße
#   [number] => 76b
#   [addition] => OG
# )
 
Zuletzt bearbeitet:
Hui, na das ist ja mal ein Pattern o_O Da wäre ich wohl alleine nicht so schnell drauf gekommen...
Danke für deine Hilfe!

Ist der Code getestet oder ungetestet?
Weil so auf den ersten Blick fallen mir Dinge auf wie der Bindestrich, der nicht escaped ist oder auch, dass du statt "\s" nur ein "normales" Leerzeichen verwendest - hab ich wohl im Beispiel vergessen, kann auch vorkommen, dass es mehrere Leerzeichen sind oder Tabulatoren o.Ä. Aber ich denke das kriege ich selbst hin ;)

Mal sehen, ob ich es heute noch testen kann, ansonsten werde ich es mir morgen mal genauer ansehen... Danke auf jeden Fall!
 
Das Skript habe ich ausprobiert und es läuft in dem Definitionsbereich. Wie Du siehst, berücksichtige ich, dass überall mehrere Leerzeichen hintereinander stehen können. Wenn Du neben den Leerzeichen auch noch andere nichtdruckbare Zeichen (e.g. Tabulator, Zeilenumbruch) an diesen Stellen berücksichtigen möchtest, dann kannst Du [ ] durch [[:blank:]] ersetzen, jedoch solltest Du dann die Eingaben auch wie folgt normalisieren:

PHP:
$normalised = preg_replace( '/[[:blank:]]+/', ' ', $input );

PS: Ich weiß noch genau, wie ich vor Jahren mich das erste Mal an reguläre Ausdrücke herangewagt habe und wie schwer es für mich war, zu verstehen, wieso, weshalb und warum es so aussehen muss und nicht anders. Aber mit der Zeit lernt man dazu und wenn man dann noch etwas Geduld hat, kann man durch gezieltes Ausprobieren die Lösung finden. Also keine Sorge, Du hast schon 90% des Weges geschafft, denn Du hast begonnen Dich damit zu beschäftigen :)
 
Falls noch jemand eine Runde basteln möchte:

(Edit: Beitrag zwei-, dreimal bearbeitet. Bitte nicht wundern.)

PHP:
<?php

/**
 *
 * @return array
 */
function getTestData()
{

    $tests_raw =
<<<EOT
Weiherweg 6a 9. OG              |  Weiherweg 6a               |  9. OG
Felberstraße 7                  |  Felberstraße 7             |
Dr.-Mack-Straße 101             |  Dr.-Mack-Straße 101        |
Ziegelstraße 18                 |  Ziegelstraße 18            |
Äußere Uferstraße               |  Äußere Uferstraße          |
Äußere Uferstraße 76 B OG       |  Äußere Uferstraße 76b      |  OG
Trettachstraße 12 5.OG          |  Trettachstraße 12          |  5.OG
Kantstraße 11                   |  Kantstraße 11              |
Buchenstraße 27 b               |  Buchenstraße 27b           |
Landrat-Dr.-Frey-Pla 5 a 8. OG  |  Landrat-Dr.-Frey-Pla 5a    |  8. OG
Gögginger Straße 13             |  Gögginger Straße 13        |
Königsbrunner Straße 33a        |  Königsbrunner Straße 33a   |
Hochfeldstraße10                |  Hochfeldstraße 10          |
Vogelmauer 78 a OG 2            |  Vogelmauer 78a             |  OG 2
Pfarrer-Bogner-Straß 16 1. OG   |  Pfarrer-Bogner-Straß 16    |  1. OG
Provinostraße 1 9 St.           |  Provinostraße 1            |  9 St.
Curtiusstraße 2 1. OG           |  Curtiusstraße 2            |  1. OG
Haßlerstraße 1 RH               |  Haßlerstraße 1             |  RH
Waterloostraße 6 EG             |  Waterloostraße 6           |  EG
Langemarckstraße 3OG            |  Langemarckstraße           |  3OG
Matineeplan12Z1OG               |  Matineeplan 12z            |  1OG
Straße des 17. Juni 2 EG        |  Straße des 17. Juni 2      |  EG
EOT;

    $tmp = str_replace(array("\r\n", "\r"), "\n", $tests_raw);

    $tests = array();

    foreach (explode("\n", $tmp) as $element) {
        $parts = explode('|', $element);

        if (3 !== count($parts)) {
            printf("[E] Formatting error in test data. Line: %s\n", $element);
            continue;
        }

        $tests[] = array(
            'input'     => trim($parts[0]),
            'street'    => trim($parts[1]),
            'street_ad' => trim($parts[2])
        );
    }

    return $tests;
}

/**
 *
 * @param string $value
 * @return array
 */
function match_address( $value ) {
  static $pattern = '/^
    ([a-zäöüß\x20.-]+)               # Straßenname
    (?:
      [\x20]+([0-9]*[\x20]*[a-z]?)   # Hausnummer (optional)
      (?:
        [\x20]+([a-z0-9.\x20]+)      # Zusatz (optional)
      )?
    )?
  $/iux';

  $matches = array();

  preg_match( $pattern, $value, $matches );

  if ( !isset( $matches[ 1 ] ) ) {
      $matches[ 1 ] = '';
  }

  if ( !isset( $matches[ 2 ] ) ) {
    $matches[ 2 ] = '';
  } else {
    $matches[ 2 ] = strtolower( str_replace( ' ', '', $matches[ 2 ] ) );
  }

  if ( !isset( $matches[ 3 ] ) ) {
    $matches[ 3 ] = '';
  }

  return array(
    'street'   => $matches[ 1 ],
    'number'   => $matches[ 2 ],
    'addition' => $matches[ 3 ]
  );
}



$error_tpl = "[E] %s
        Input:    \"%s\"
        Expected: \"%s\"
        Given:    \"%s\"\n\n";

foreach (getTestData() as $test) {
    $output = match_address($test['input']);

    $street = $output['street'];

    if ('' !== $output['number']) {
        $street .= ' ' . $output['number'];
    }

    if ($test['street'] !== $street) {
        printf(
            $error_tpl,
            'Street/Number', $test['input'], $test['street'], $street
        );
    }

    if ($test['street_ad'] !== $output['addition']) {
        printf(
            $error_tpl,
            'Addition', $test['input'], $test['street_ad'], $output['addition']
        );
    }
}

Code:
[E] Street/Number
        Input:    "Hochfeldstraße10"
        Expected: "Hochfeldstraße 10"
        Given:    ""

[E] Street/Number
        Input:    "Langemarckstraße 3OG"
        Expected: "Langemarckstraße"
        Given:    ""

[E] Addition
        Input:    "Langemarckstraße 3OG"
        Expected: "3OG"
        Given:    ""

[E] Street/Number
        Input:    "Matineeplan12Z1OG"
        Expected: "Matineeplan 12z"
        Given:    ""

[E] Addition
        Input:    "Matineeplan12Z1OG"
        Expected: "1OG"
        Given:    ""

[E] Street/Number
        Input:    "Straße des 17. Juni 2 EG"
        Expected: "Straße des 17. Juni 2"
        Given:    ""

[E] Addition
        Input:    "Straße des 17. Juni 2 EG"
        Expected: "EG"
        Given:    ""
 
Zuletzt bearbeitet:
Kann ich bestätigen, haut noch nicht hundertprozentig hin ;) Aber ich werde mich die nächsten Tage kaum damit beschäftigen können, zu viel anderes zu tun...
Sobald ich wieder mehr Luft habe probiere ich mich noch ein wenig an dem angegebenen Pattern.
 
Zurück