named groups in oniguruma 16. Jun 2010

Ich habe Oniguruma bisher nur in Textmate verwendet. Darüber hinaus findet es aber auch noch bei Ruby 1.9 Verwendung. In diesem Zusammenhang machen dann auch benannte Gruppen Sinn. Wenn man in Ruby 1.8 Gruppen referenzieren möchte dann geht das nur über ihre Position.

m = /(\w+) (\w+)/.match("Kalle Anka")
puts "#{m[1]} gehört zur Familie #{m[2]}"

Das ist praktikabel, aber nicht optimal im Sinne der Lesbarkeit. Wenn man nun die Lesbarkeit verbessert, dann bläht sich der Code auf.

m = /(\w+) (\w+)/.match("Kalle Anka")
vorname = m[1]
nachname = m[2]
puts "#{vorname} gehört zur Familie #{nachname}"

Durch Oniguruma In Ruby 1.9 läßt sich das ganze relativ elegant ausdrücken.

m = /(?<Vorname>\w+) (?<Nachname>\w+)/.match("Kalle Anka")
puts "#{m["Vorname"]} gehört zur Familie #{m["Nachname"]}"

Aus meiner Perspektive erhöht sich nicht nur Lesbarkeit der Ausgabezeile sondern auch die Wartbarkeit des regulären Ausdrucks. Jeder der schonmal einen umfangreicheren regulären Ausdruck erstellt hat und zwei Jahre später nochmal damit in Kontakt gekommen ist, der weiß wie unintuitiv komplexe reguläre Ausdrück sind. Ich denke benannte Gruppen können hier einen sinnvollen Beitrag zur besseren Wartbarkeit liefern. Eine andere Sache ist, dass sich bei mehreren Vergleichen schnell ein Wildwuchs an Variablen ergibt.

var1 = /(?<Vorname>\w+) (?<Nachname>\w+)/.match("Kalle Anka")
var2 = /(?<Strasse>\w+) (?<Hausnummer>\w+)/.match("Entenstrasse 13")
var3 = /(?<Postleitzahl>) (?<Ortschaft>\w+)/.match("368 Ankeborg")
puts("#{var1["Vorname"]} wohnt in der #{var2["Strasse"]} in #{var3["Ortschaft"]}")

Dem läßt sich begegnen indem man die MatchData-Klasse um eine Methode zur Konvertierung in einen Hash erweitertet.

class MatchData
  def to_h
    Hash[*self.names.zip(self.captures).flatten]
  end
end

Dann kommt man mit einer Variable aus.

h = (/(?<Vorname>\w+) (?<Nachname>\w+)/.match("Kalle Anka").to_h) 
h.merge!(/(?<Strasse>\w+) (?<Hausnummer>\w+)/.match("Entenstrasse 13").to_h)
h.merge!(/(?<Postleitzahl>\w+) (?<Ortschaft>\w+)/.match("368 Ankeborg").to_h)
puts("#{h["Vorname"]} wohnt in der #{h["Strasse"]} in #{h["Ortschaft"]}")

Dafür wird das ganze jetzt aber etwas verbose. Wäre es nicht prima, wenn die Hash-Klasse einen Push-Operator besäße?

class Hash
  def <<(other_hash)
    merge!(other_hash)
  end
end

Okay, ich denke so kann man das stehen lassen.

h = /(?<Vorname>\w+) (?<Nachname>\w+)/.match("Kalle Anka").to_h
h << /(?<Strasse>\w+) (?<Hausnummer>\w+)/.match("Entenstrasse 13").to_h
h << /(?<Postleitzahl>) (?<Ortschaft>\w+)/.match("368 Ankeborg").to_h
puts("#{h["Vorname"]} wohnt in der #{h["Strasse"]} in #{h["Ortschaft"]}")
 

Kommentar schreiben

Markdown Syntax