Zum Inhalt springen

WadokuJT-Datensätze extrahieren mit Ruby

14/09/2011

WadokuJT ist ein freies Japanisch-Deutsch Wörterbuch von Dr. Ulrich Apel, der momentan in Tübingen lehrt.
Ich hatte letztens die Aufgabe, seine Originaldatensätze für eine weitere Verarbeitung zu extrahieren.
Da es sich dabei um mehr als 1000,000 Datensätze handelt, kann man das leider nicht im Word/Open Office per Hand und Copy/Paste überarbeiten…wie schade…;D.
Ich habe mich für eine programmatische Lösung dieses Problems entschieden, dafür wählte ich die Sprache Ruby(in Java wäre ich dabei sicherlich gestorben…bin ja noch ein Babyprogrammierer…ó_ò).
Die Originaldatensätze sehen bspsweise so aus:

1655423	あ [1]; ア	あ [1]	(<POS: N.>) [1]<MGr: <TrE: <HW n: a>>; <TrE: <HW n: A>>; <TrE: <HW m: Vokal> „<Topic: a>“>; <TrE: <HW m: Lautwert> „<Topic: a>“>> // <MGr: <TrE: <HW m: Lautwert> „<Topic: a>“ in der 50-Laute-Tafel>; <TrE: erstes <HW n: Zeichen> der ersten Reihe der 50-Laute-Tafel>; <TrE: 36. <HW n: Zeichen> des Iroha-Gedichtes>>. [2]<MGr: <TrE: <HW n: Hiragana> „<Topic: a>“>; <TrE: <Jap.: あ>>; <TrE: <HW n: Katakana> „<Topic: a>“>; <TrE: <Jap.: ア>>>.	名			HE					あ	

Als Endergebnis sollte rauskommen:

1655423	あ [1]; ア	あ [1]	<TrE: <HW n: a>>
1655423	あ [1]; ア	あ [1]	<TrE: <HW n: A>>
1655423	あ [1]; ア	あ [1]	<TrE: <HW m: Vokal> „<Topic: a>“>
1655423	あ [1]; ア	あ [1]	<TrE: <HW m: Lautwert> „<Topic: a>“>>
1655423	あ [1]; ア	あ [1]	<TrE: <HW m: Lautwert> „<Topic: a>“ in der 50-Laute-Tafel>
1655423	あ [1]; ア	あ [1]	<TrE: erstes <HW n: Zeichen> der ersten Reihe der 50-Laute-Tafel>
1655423	あ [1]; ア	あ [1]	<TrE: 36. <HW n: Zeichen> des Iroha-Gedichtes>
1655423	あ [1]; ア	あ [1]	<TrE: <HW n: Hiragana> „<Topic: a>“>
1655423	あ [1]; ア	あ [1]	<TrE: <Jap.: あ>>
1655423	あ [1]; ア	あ [1]	<TrE: <HW n: Katakana> „<Topic: a>“>
1655423	あ [1]; ア	あ [1]	<TrE: <Jap.: ア>>

Ein vollständiger Wadoku-Eintrag, wie im ersten Beispiel, setzt sich zusammen aus:
„wadoku_id“ \t „writing“ \t „midashigo“ \t „kana“ \t „definition“ \t der Rest(interessiert erst mal nicht)…
Da für meine Aufgabe nur der Teil bis inklusiv „definition“ gebraucht wird, habe ich zunächst eine neue Datei erstellt mit den vereinfachten Datensätzen.


#Hilfsprozedur um einzelne Einträge zu kürzen
def truncate entry
  array = entry.split("\t") 
   #Die Fallunterscheidung, falls "kana" nicht vorhanden ist...eigentl. nicht nötig...was mir erst jetzt aufgefallen ist
  array[3] == "" ? array.values_at(0,1,3,4).join("\t") : array.values_at(0,1,2,4).join("\t")
end

#eine neue Datei aus der alten generieren
#wdk = Name der Wadoku-Raw-Datei
def generate wdk 
  content = File.open(wdk, "r").readlines
  new_content = content.map{|entry| truncate entry}.join("\n")
  file = File.new("wdk_list", "w") #neue Datei öffnen mit Schreibrecht
  file.puts new_content
  file.close
end

Die neue Datei mit dem Namen „wdk_list“ enthält nur die 4 Komponente, die für die weitere Verarbeitung wichtig sind(Dieser Schritt hätte man sich eigentl. auch sparen können…aber sowas fällt nur hinterher auf…MANN):

1655423	あ [1]; ア	あ; ア	あ [1]	(<POS: N.>) [1]<MGr: <TrE: <HW n: a>>; <TrE: <HW n: A>>; <TrE: <HW m: Vokal> „<Topic: a>“>; <TrE: <HW m: Lautwert> „<Topic: a>“>> // <MGr: <TrE: <HW m: Lautwert> „<Topic: a>“ in der 50-Laute-Tafel>; <TrE: erstes <HW n: Zeichen> der ersten Reihe der 50-Laute-Tafel>; <TrE: 36. <HW n: Zeichen> des Iroha-Gedichtes>>. [2]<MGr: <TrE: <HW n: Hiragana> „<Topic: a>“>; <TrE: <Jap.: あ>>; <TrE: <HW n: Katakana> „<Topic: a>“>; <TrE: <Jap.: ア>>>.	

Anschließend konzentrieren wir uns auf die „definition“, in der die „TrE“-Tags sind, die wir aber einzel haben möchten.(TrE = Translations Equivalent; HW = Headword; MGr = Meaning Group)
Meine Überlegung war, dass ich zunächst einen Array haben möchte, mit nur den „TrE“-Tags.


=>  [<TrE: <HW n: a>>, <TrE: <HW n: A>>, <TrE: <HW m: Vokal> „<Topic: a>“>, <TrE: <HW m: Lautwert> „<Topic: a>“>>, <TrE: <HW m: Lautwert> „<Topic: a>“ in der 50-Laute-Tafel>, <TrE: erstes <HW n: Zeichen> der ersten Reihe der 50-Laute-Tafel>, <TrE: 36. <HW n: Zeichen> des Iroha-Gedichtes>,...]

Dafür musste ich mir einen passenden Regex(regulären Ausdruck) ausdenken, der alles innerhalb des „TrE“-Tags parset.
Das erste, was mir eingefallen ist(oder ergegooglet habe) war:


/(<TrE.+?>)/
	

Aber leider parset der nicht richtig, weil der nur bis zum ersten „>“ geht. Bei Tags wie z.B: <TrE: 36. <HW n: Zeichen> des Iroha-Gedichtes>> in der 50-Laute-Tafel> hat die Hälfte gefehlt.
Mit Hilfe von Rubular konnte ich aber schließlich einen Ausdruck finden, der richtig zu sein schien:


(<TrE.+?)(>;|>\.|\s\/\/)
	

Und damit konnte ich meine Methode schreiben:


def parse defi
  array = defi.scan(/(<TrE.+?)(>;|>\.|\s\/\/)/).flatten
  #bei einigen Tags fehlt der ">" am Ende
  array.select{|e| e.include? "<TrE"}.map{|e| e.end_with?(">") ? e : e + ">"}
end
	

Nachdem es nun möglich war, die „TrE“-Tags zu extrahieren, musste ich nur noch die einzelnen Übersetzungsequivalente aus dem Array, mit dem entsprechenden „wadoku_id“, „writing“, „midashigo“ oder „kana“ richtig in ein neues Dokument eintragen.


def generate2 wdk
  content = File.open(wdk, "r").readlines
  new_content = content.map do |entry|
                  #der vordere Teil mit "wadoku_id", "writing", "midashigo" oder "kana"
                  pre = entry.split("\t").values_at(0,1,2).join("\t")
                  #die TrEs zusammengefasst in Array
                  tre_array = parse(entry.split("\t")[3])
                  #pre + tre
                  tre_array.map{|tre| pre + "\t" + tre}.join("\n")
                end

  #das ganze wird in die neue Datei "wdk_list2" reingeschrieben
  file = File.new("wdk_list2", "w")
  file.puts new_content
  file.close
end

Die Methoden habe ich in der Datei „wdk_method.rb“ gespeichert und wie folgt in irb ausgeführt:


ruby-1.9.2-p180 :098 > load "wdk_method.rb"
=> true 
ruby-1.9.2-p180 :099 > generate "WaDokuNormal.tab" #die wadoku-raw Datei mit heimtückischen Groß- und Kleinschreibungen 
=> nil
ruby-1.9.2-p180 :100 > generate2 "wdk_list"
=> nil

Voila!…da habe ich meine extrahierte Version der Datensätze.
Leider mit Schönheitsfehlern wie z.B., dass bei manchen „TrE“-Tags der Schluss Tag „>“ fehlt, wegen meines nicht ganz so professionellen Regexes. Außerdem enthält die Datei massenhafte „\n“s („Carriage Return“-Zeichen), aus unerfindlichen Gründen(liegt wahrscheinl. daran, dass ich die Funktionsweise von IO.readlines nicht ganz kapiert habe. Und im Moment scheint die ruby-doc keine Auskunft über IO geben zu wollen).
Bevor die Profis jetzt anfangen über mich zu lachen, zeig ich noch, was ich daraufhin aus meiner Lächerlichkeit zur Verbesserung der Datei gemacht habe:

def kill_n wdk
  t = File.open(wdk, "r").readlines.uniq
  file = File.open(wdk, "w+")
  file.puts t
  file.close
end

Die „kill_n“-Methode soll alle überflüssigen „\n“s in der Datei killen…;D So jetzt habe ich es verdient, ausgelacht zu werden.

From → Programmierung

One Comment
  1. Johnc980 permalink

    I just like the helpful information you provide on your articles. I will bookmark your blog and test once more here frequently. I’m moderately certain I will learn many new stuff right here! Best of luck for the next! gefdggdaaddf

Hinterlasse einen Kommentar