Pattern Matching

Mit unserem bisherigen Wissen müssen wir pro möglicher Rufnummer immer eine eigene Extension schreiben. Dies würde schon nach kurzer Zeit sehr lange und fehleranfällige Dialpläne nach sich ziehen. Sollen z.B. die Rufnummern 100 bis 109 jeweils immer den hello-world Sprachbaustein abspielen, so würde die extensions.conf wie folgt aussehen:

[general]

[apfelmus]
exten => 100,1,Answer()
exten => 100,2,Playback(hello-world)
exten => 100,3,Hangup()

exten => 101,1,Answer()
exten => 101,2,Playback(hello-world)
exten => 101,3,Hangup()

exten => 102,1,Answer()
exten => 102,2,Playback(hello-world)
exten => 102,3,Hangup()

exten => 103,1,Answer()
exten => 103,2,Playback(hello-world)
exten => 103,3,Hangup()

exten => 104,1,Answer()
exten => 104,2,Playback(hello-world)
exten => 104,3,Hangup()

exten => 105,1,Answer()
exten => 105,2,Playback(hello-world)
exten => 105,3,Hangup()

exten => 106,1,Answer()
exten => 106,2,Playback(hello-world)
exten => 106,3,Hangup()

exten => 107,1,Answer()
exten => 107,2,Playback(hello-world)
exten => 107,3,Hangup()

exten => 108,1,Answer()
exten => 108,2,Playback(hello-world)
exten => 108,3,Hangup()

exten => 109,1,Answer()
exten => 109,2,Playback(hello-world)
exten => 109,3,Hangup()

Unter Verwendung eines Patterns in Form einer Regular Expression (auch Regex genannt)

[Tipp]

Definition Regular Expression:

"Reguläre Ausdrücke (Abk. RegExp oder Regex, engl. regular expressions) dienen der Beschreibung von (Unter-)Mengen von Zeichenketten mit Hilfe syntaktischer Regeln. Sie finden vor allem in der Softwareentwicklung Verwendung; für fast alle Programmiersprachen existieren Implementierungen." (zitiert aus http://de.wikipedia.org/wiki/Regul%C3%A4rer_Ausdruck )

sieht der gleiche Dialplan gleich viel handlicher aus:

[general]

[apfelmus]
exten => _10X,1,Answer()
exten => _10X,2,Playback(hello-world)
exten => _10X,3,Hangup()

Das Pattern _10X beschreibt den Zahlenraum von 100 bis 109.

[Wichtig]

Man benutzt für die Beschreibung von dieses Prozesses häufig das englische Verb match und das Substantiv Pattern. "Pattern" kann mit Suchmuster übersetzt werden. "match" lässt sich schwer eins zu eins ins Deutsche übersetzen und ist am einfachsten mit einem Beispiel zu beschreiben: Ein Pattern ist "_10X" und dieses Pattern matcht auf den Zahlenraum 100 bis 109. Es matcht also nicht auf die Zahl 110.

[Anmerkung]

Die Begriffe Pattern und Regular Expression werden in vielen Dokumentationen sehr beliebig eingesetzt. Auch dieses Buch leidet unter diesem Problem. Formal korrekt ist sicherlich der Begriff Pattern, aber die meisten Programmierer werden den Begriff Regular Expression benutzen.

Syntax

Ein Pattern wird immer mit einem Unterstrich (_) vor dem eigentlichen Suchmuster eingeleitet:

exten => _Regular Expression,Prioritaet,Applikation

Eine Regular Expression kann in Asterisk aus den folgenden Elementen[11] bestehen:

[ABC]

Die Ziffern A, B und C. Beispiel für die Zahlen 34, 37 und 38:

exten => _3[478],1,NoOp(Test)
[A-B]

Beliebige Ziffer von A bis B. Beispiel für alle Zahlen von 31 bis 35:

exten => _3[1-5],1,NoOp(Test)

(z.B. auch [25-8] möglich für die Ziffern 2,5,6,7,8)

X

Beliebige Ziffer von 0 bis 9. Beispiel für alle Zahlen von 300 bis 399:

exten => _3XX,1,NoOp(Test)
Z

Beliebige Ziffer von 1 bis 9. Beispiel für alle Zahlen von 31 bis 39:

exten => _3Z,1,NoOp(Test)
N

Beliebige Ziffer von 2 bis 9. Beispiel für alle Zahlen von 32 bis 39:

exten => _3N,1,NoOp(Test)
.

Eine oder mehrere beliebige Ziffer(n). Beispiel für alle Nummer, die mit einer 0 beginnen:

exten => _0.,1,NoOp(Test)
[Anmerkung]

Das Pattern _. sollten Sie nicht verwenden! Es trifft auch auf besondere Extensions wie i, t oder h zu. Benutzen Sie stattdessen _X. oder _X falls nötig.

!

Eine oder mehrere beliebige Ziffer(n) - ab Asterisk 1.4. Dieser besondere Platzhalter trifft zu, sobald unzweifelhaft nicht eine andere explizite Nummer im Dialplan gewählt wird. Hebt dann sofort die Leitung ab für „overlap dialing“. Hier nur der Vollständigkeit halber erwähnt.

[Wichtig]

Ein beliebter Fehler ist es am Anfang einer Regular Expression das Underscore "_" Zeichen zu vergessen. Für Asterisk ist aber die Extension XXX ebenfalls eine vollkommen sinnvolle Extension (da SIP ja nicht nur Zahlen, sondern auch Buchstaben als Zieladresse kennt). Entsprechend wird es auch keine Fehlermeldung geben. Dummerweise wird das Pattern aber auch nie matchen, weil es nicht als Pattern (also mit dem _) eingegeben wurde.

Testen mit dialplan show

Nehmen wir mal an, das in unserer extensions.conf der folgende Dialplan steht:

[general]

[meine-telefone]
exten => 23,1,Answer()
exten => 23,2,Playback(hello-world)
exten => 23,3,Hangup()

Dann können wir im CLI von Asterisk (das ist die Interface, das bei einem bereits laufenden Asterisk mit asterisk -r gestartet werden kann) mit dem Befehl dialplan show (auf Asterisk 1.2: show dialplan) den aktuellen Dialplan anzeigen:

*CLI> dialplan show
[ Context 'default' created by 'pbx_config' ]

[ Context 'meine-telefone' created by 'pbx_config' ]
  '23' =>           1. Answer()                                   [pbx_c
onfig]
                    2. Playback(hello-world)                      [pbx_c
onfig]
                    3. Hangup()                                   [pbx_c
onfig]

[ Context 'parkedcalls' created by 'res_features' ]
  '700' =>          1. Park()                                     [res_f
eatures]

-= 2 extensions (4 priorities) in 3 contexts. =-
*CLI>

Das CLI zeigt jetzt alle Asterisk bekannten Wählregeln auf. Deshalb gibt es auch noch einen Context "parkedcalls", den wir gar nicht wissentlich aktiviert haben (dieser wird standardmässig in der features.conf aktiviert und stört uns jetzt nicht weiter). Wenn wir uns nur auf den Dialplan für den Context meine-telefone interessieren, so können wir diesen mit dialplan show meine-telefone abrufen:

*CLI> dialplan show meine-telefone
[ Context 'meine-telefone' created by 'pbx_config' ]
  '23' =>           1. Answer()                                   [pbx_c
onfig]
                    2. Playback(hello-world)                      [pbx_c
onfig]
                    3. Hangup()                                   [pbx_c
onfig]

-= 1 extension (3 priorities) in 1 context. =-
*CLI> 

Der Befehl dialplan show kann aber nicht nur ganze Contexte anzeigen, sondern auch sagen was passiert, wenn ich eine bestimmte Nummer wähle. Wenn ich mit einem Telefon das im Context meine-telefone ist die Nummer 25 anrufe, dann kann ich mit dialplan show 25@meine-telefone anzeigen was passiert:

*CLI> dialplan show 25@meine-telefone
There is no existence of 25@meine-telefone extension
*CLI>

Es wird also nichts passieren, weil es keinen Match für die von mir gewählte Extension 25 gibt. Wenn ich das gleiche für die 23 mache, dann gibt es folgende Ausgabe:

*CLI> dialplan show 23@meine-telefone
[ Context 'meine-telefone' created by 'pbx_config' ]
  '23' =>           1. Answer()                                   [pbx_c
onfig]
                    2. Playback(hello-world)                      [pbx_c
onfig]
                    3. Hangup()                                   [pbx_c
onfig]

-= 1 extension (3 priorities) in 1 context. =-
*CLI> 

Wenn ich in allen verfügbaren Contexten nach einem Match für die 23 suchen möchte, so geht das mit dialplan show 23@

*CLI> dialplan show 23@
[ Context 'meine-telefone' created by 'pbx_config' ]
  '23' =>           1. Answer()                                   [pbx_c
onfig]
                    2. Playback(hello-world)                      [pbx_c
onfig]
                    3. Hangup()                                   [pbx_c
onfig]

-= 1 extension (3 priorities) in 1 context. =-
*CLI>

Erweitern wir unseren Dialplan mal um einen weiteren Context:

[general]

[meine-telefone]
exten => 23,1,Answer()
exten => 23,2,Playback(hello-world)
exten => 23,3,Hangup()

[abteilung-z]
exten => _2X,1,Answer()
exten => _2X,2,Playback(hello-world)
exten => _2X,3,Hangup()

Und jetzt führen wir noch mal dialplan show 23@ aus (vorher müssen wir natürlich Asterisk mit reload im CLI sagen, das es den neuen Dialplan einlesen soll):

*CLI> dialplan show 23@
[ Context 'abteilung-z' created by 'pbx_config' ]
  '_2X' =>          1. Answer()                                   [pbx_c
onfig]
                    2. Playback(hello-world)                      [pbx_c
onfig]
                    3. Hangup()                                   [pbx_c
onfig]

[ Context 'meine-telefone' created by 'pbx_config' ]
  '23' =>           1. Answer()                                   [pbx_c
onfig]
                    2. Playback(hello-world)                      [pbx_c
onfig]
                    3. Hangup()                                   [pbx_c
onfig]

-= 2 extensions (6 priorities) in 2 contexts. =-
*CLI> 

Es werden also alle matchenden Extensions anzeigt. Um im obigen Beispiel zu bleiben, probieren wir das jetzt auch noch mal mit dialplan show 25@ aus:

*CLI> dialplan show 25@
[ Context 'abteilung-z' created by 'pbx_config' ]
  '_2X' =>          1. Answer()                                   [pbx_c
onfig]
                    2. Playback(hello-world)                      [pbx_c
onfig]
                    3. Hangup()                                   [pbx_c
onfig]

-= 1 extension (3 priorities) in 1 context. =-
*CLI>

Logischerweise gibt es dabei nur einen Treffer und der ist im Context abteilung-z. Sollten Sie also mit einem Telefon, das im Context meine-telefone arbeitet die 25 wählen, so werden Sie trotzdem kein hello-world hören, denn dies funktioniert nur bei Telefonen, die auch im Context abteilung-z arbeiten.

Wann matcht welches Pattern?

Pattern Matching in Asterisk ist bei großen Dialplänen eine trickreiche Angelegenheit. Asterisk geht nämlich nicht wie allgemein angenommen wird plump von oben nach unten den Dialplan durch. Nein, es priorisiert innerhalb der Patterns!

Je exakter ein Pattern matcht, desto höher ist die Wahrscheinlichkeit das es matcht. Asterisk geht allerdings - bevor es eine Entscheidung trifft - den ganzen Context durch. Es könnte ja sein, das ein anderes Pattern noch besser matcht.

Beispiel:

[verkauf]
exten => _12X.,1,NoOp{12X}
exten => 12345,1,NoOp(12345}
exten => _1234.,1,NoOp{1234.}

Um heraus zufinden welches welches Pattern matched, wenn die 12345 gewählt wird, können wir dies mit dialplan show 12345@verkauf überprüfen:

*CLI> dialplan show 12345@verkauf
[ Context 'verkauf' created by 'pbx_config' ]
  '12345' =>        1. NoOp(12345})                               [pbx_c
onfig]
  '_1234.' =>       1. NoOp{1234.}()                              [pbx_c
onfig]
  '_12X.' =>        1. NoOp{12X}()                                [pbx_c
onfig]

-= 3 extensions (3 priorities) in 1 context. =-
*CLI> 

Asterisk zeigt alle Treffer, aber priorisiert die Zeile in der 12345,1,NoOP{12345} steht. Die höchste Priorität wird immer ganz oben angezeigt.

Jetzt kontrollieren wir das noch für die Nummer 12346 mit dem Befehle dialplan show 12346@verkauf

*CLI> dialplan show 12346@verkauf
[ Context 'verkauf' created by 'pbx_config' ]
  '_1234.' =>       1. NoOp{1234.}()                              [pbx_c
onfig]
  '_12X.' =>        1. NoOp{12X}()                                [pbx_c
onfig]

-= 2 extensions (2 priorities) in 1 context. =-
*CLI> 

Auch hier bekommt das Pattern mit dem "besten" Treffer die höchste Priorität.

[Wichtig]

Es ist nicht wichtig, in welcher Reihenfolge Patterns im Dialplan geschrieben werden! Es ist nur wichtig wie genau ein Pattern matcht. Je genauer, desto höher wird es priorisiert.

[Warnung]

Es gibt eine Sonderregel für das Pattern _.

"_." matcht immer und hat auch immer die höchste Priorität. Es ist also egal, was Sie sonst noch in diesem Context für Regeln haben! Es wird immer nur die Regel mit dem Pattern "_." ausgeführt. Man sollte also lieber ein "_X." nehmen, ausser man ist sich absolut sicher und weiss was das Pattern "_." bewirkt.

Auch wenn die Reihenfolge von Pattern nicht immer ganz trival ist, gibt es eine einfache Debugging Möglichkeit. Mit show dialplan 12345@verkauf lässt sich der Dialplan für die gewählte Nummer 12345 im Context verkauf auflisten. So kann man für spezielle Nummern überprüfen, ob auch die dafür vorgesehene Regel matcht.

Sonderregel für das Pattern _. in Asterisk 1.2

Damit das Leben eines Asterisk Administrators nicht zu einfach wird, hat sich Digium noch eine Besonderheit für das Pattern "_." in der Asterisk Version 1.2 ausgedacht. Obwohl dieses Pattern das allgemeinste und damit von der Logik her das mit der geringsten Priorität sein müsste, ist es genau anders rum!

[Warnung]

_. bekommt in Asterisk Version 1.2 immer die höchste Priorität!

[Anmerkung]

Bitte beachten Sie, dass der CLI-Befehl show dialplan zwar auch noch in der Version 1.4 funktioniert, aber unerwünscht ist. Deshalb sind die Aufrufe in der Version 1.2 show dialplan und in der Version 1.4 dialplan show.

Probieren wir noch einmal unseren obigen Dialplan mit einer zusätzlichen Extension "_." aus:

[verkauf]
exten => _12X.,1,NoOp{12X}
exten => 12345,1,NoOp(12345}
exten => _1234.,1,NoOp{1234.}

exten => _.,1,NoOp{Bingo}

Wenn wir jetzt die Rufnummer 12346 ausprobieren wollen, so bekommen wir mit dem Befehl dialplan show 12346@verkauf in der Version 1.4 folgende Ausgabe:

*CLI> dialplan show 12346@verkauf
[ Context 'verkauf' created by 'pbx_config' ]
  '_1234.' =>       1. NoOp{1234.}()                              [pbx_c
onfig]
  '_12X.' =>        1. NoOp{12X}()                                [pbx_c
onfig]
  '_.' =>           1. NoOp{Bingo}()                              [pbx_c
onfig]

-= 3 extensions (3 priorities) in 1 context. =-
*CLI>

In Asterisk 1.2 bekommt der Befehl show dialplan 12346@verkauf aber folgende Ausgabe:

*CLI> show dialplan 12346@verkauf
[ Context 'verkauf' created by 'pbx_config' ]
  '_.' =>           1. NoOp{Bingo}()                              [pbx_c
onfig]
  '_1234.' =>       1. NoOp{1234.}()                              [pbx_c
onfig]
  '_12X.' =>        1. NoOp{12X}()                                [pbx_c
onfig]

-= 3 extensions (3 priorities) in 1 context. =-
*CLI>

Deshalb sollte man als "Restesammler" (wenn überhaupt) nur das Pattern _X. benutzen. Der folgende Dialplan wird in den Asterisk Versionen 1.2 und 1.4 gleich behandelt:

[verkauf]
exten => _12X.,1,NoOp{12X}
exten => 12345,1,NoOp(12345}
exten => _1234.,1,NoOp{1234.}

exten => _X.,1,NoOp{Bingo}

Die Prioritäten sind in beiden Asterisk Versionen wie folgt:

*CLI> dialplan show 12346@verkauf
[ Context 'verkauf' created by 'pbx_config' ]
  '_1234.' =>       1. NoOp{1234.}()                              [pbx_c
onfig]
  '_12X.' =>        1. NoOp{12X}()                                [pbx_c
onfig]
  '_X.' =>          1. NoOp{Bingo}()                              [pbx_c
onfig]

-= 3 extensions (3 priorities) in 1 context. =-
*CLI> 



[11] Es gibt noch weitere Elemente, die im deutschen Sprachraum aber im Allgemeinen wenig Sinn machen. Aus diesem Grund werden sie hier nicht aufgeführt.