[GastForen Programmierung/Entwicklung AppleScript Datumskandidaten herausfiltern

  • Suche
  • Hilfe
  • Lesezeichen
  • Benutzerliste
Themen
Beiträge
Moderatoren
Letzter Beitrag

Datumskandidaten herausfiltern

Hans Haesler
  
Beiträge gesamt: 5826

9. Sep 2010, 10:57
Beitrag # 1 von 27
Bewertung:
(5551 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Scripter,

im Thema http://www.hilfdirselbst.ch/..._P450750.html#450750 geht es darum, aus einem Text die Zeichenfolgen "Ziffern mit Punkten" herauszufiltern, welche ein Datum sein könnten.

Als Script-Neuling schlägt sich der Michael sehr gut, hat er doch Methoden entwickelt, welche die Aufgabe zuverlässig ausführen.

Wie gegen Ende jenes Themas schon erwähnt, könnte das Herauspicken der "Kandidaten" direkter geschehen. Im besagten Script wird mit "every word" zuerst eine Liste aller Worte erstellt. Dann werden in einer Schleife diese Elemente abgearbeitet und wenn sie einen Punkt enthalten und eine gewisse Länge aufweisen, an eine neue Liste gehängt. Dann werden in einer weiteren Schleife die Übriggebliebenen mit dem Punkt als Trenner zerlegt. Nur wenn sich drei Teile ergeben, werden sie einzeln in Ganzzahlen verwandelt und in der Folge wird geprüft, ob es sich um mögliche Teile eines Datums handelt.

Wenn wir einen Filter einsetzen, der nur Zeichenfolgen auflistet, welche Ziffern und zwei Punkte enthalten, dann kann auf das problematische Auflisten aller Worte verzichtet und die weiteren Test können vereinfacht werden.

Dazu braucht es aber ein Helferlein, welches in einem Text die Ziffern erkennt. Ich habe mich für die Scripting Addition Satimage.osax entschieden, weil sie mir vertrauter ist, als do-shell-script-Befehle.

Falls sich diese Scripting Addition noch nicht im Ordner "Library/ScriptingAdditions" befindet, kann man sie hier herunterladen: http://www.satimage.fr/...ompanion_osaxen.html.

Zuerst aber den Skripteditor beenden, dann im zweiten Abschnitt der Website auf den Link "Satimage osax 3.5.2 (build 360)" klicken. Die Installation erfolgt problemlos.

Jetzt kann geprüft werden, ob das Herauslösen von Datumskandidaten gelingt. Voraussetzung ist, dass die Daten in der Formatierung dd.mm.yyyy oder dd.mm.yy getippt sind.

Code
set textBlock to "Test 123.08.69 und 03.04.2010 sowie 8.09.210 oder 18.8.04 und 12.10.02 oder auch 2.34.56" 

try
set punktListe to (find text "[0-9]{2,}\\.[0-9]{2}\\.[0-9]{2,}" in textBlock with regexp, all occurrences and string result)
on error
set punktListe to {}
end try

Der try-Wickel ist zwingend notwendig. Damit kann eine Fehlermeldung verhindert werden, wenn die Textkette keine Kombination von Ziffern/Punkt/Ziffern/Punkt/Ziffern enthält (oder keine dem definierten Muster entspricht).

Der Satimage-Befehl setzt das Ergebnis in die Variable punktListe.

Die einzelnen Teile des Befehls:
find text = finde den Text,
welcher dem Muster zwischen den Anführungszeichen entspricht,
in textBlock = im String textBlock,
with regexp = reguläre Ausdrücke verwenden
all occurrences = alle Vorkommen
and string result = nur die Textketten

Mit der letzten Option wird das Ergebnis auf die gefundenen Strings beschränkt. Sonst würde find text auch die Position im Originaltext und die Länge der gefundenen Strings zurückgeben.

Zum Such-Muster ...

Code
[0-9] Bedeutet: eine beliebige Ziffer zwischen 0 und 9. 
{2,} Das heisst: zwei oder mehrere Ziffern.
\\. Weil der Punkt alleine "ein beliebiges Zeichen" bedeuten würde,
muss diese Eigenschaft mit einem davorgestellen Backslash deaktiviert werden.
Und weil der Backslash somit ebenfalls ein Sonderzeichen ist, muss er mit
einem weiteren Backslash deaktiviert werden.
[0-9] Wieder eine beliebige Ziffer zwischen 0 und 9.
{2} Bedeutet: exakt zwei Ziffern (weil ohne Komma)
\\. Nochmals einen Punkt
[0-9]{2,} Zum Schluss erneut zwei oder mehrere Ziffern

Nur die Gruppe in der Mitte darf auf zwei Stellen fixiert werden. Bei der ersten und der letzten muss man alle vorhandenen aufnehmen. Sonst könnte bei einer Beschränkung auf ebenfalls je zwei aus dem Beispiel 123.12.456 das gültige Datum 23.12.45 werden.

Das Ergebnis des obenstehenden Beispiels: {"123.08.69", "03.04.2010", "12.10.02"}

Es sind also schon drei "unmögliche" weggefallen. Die restlichen werden in einem weiteren Abschnitt untersucht und behalten, falls sie die Kriterien (Tag = 2 Stellen, zwischen 1 und 31; Monat = 2 Stellen, zwischen 1 und 12; Jahr = 2 oder 4 Stellen) erfüllen.

Gruss, Hans
X

Datumskandidaten herausfiltern

michael m.
Beiträge gesamt: 162

9. Sep 2010, 11:41
Beitrag # 2 von 27
Beitrag ID: #450949
Bewertung:
(5537 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Hans,

ist ja unglaublich.
So kurzer Code.

Ich denke auf diese Methode wäre ich vielleicht Monate später drauf gekommen, wenn ich mal mit dem Thema "osax" Bibliotheken beschäftigt hätte.

So viel ich verstehe sind das zusätzliche Befehlsbibliotheken.
Irgendwann kommt das noch. Rom ist auch nicht an einem Tag erbaut worden.

Vorteil ist nur dass ich keine Zusatzbibliotheken brauche, dafür aber der Rechner mehr leisten muss. Habe ja einen QuadCore i7 mit 8 GB Ram soll er mal was machen, ist besser als langweilen.

Aber ich finde es toll, wenn man mehrere Wege kennt.

Viele Grüsse
Michael


als Antwort auf: [#450938]

Datumskandidaten herausfiltern

Hans Haesler
  
Beiträge gesamt: 5826

9. Sep 2010, 15:39
Beitrag # 3 von 27
Beitrag ID: #450980
Bewertung:
(5521 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Michael,

ja, das ist erstaunlich wenig Code, um viel direkter ans Ziel zu gelangen.

Auch mit einer leistungsfähigen Maschine lohnt es sich, diese Abkürzung zu verwenden. Nicht unbedingt wegen der Geschwindigkeit, sondern weil das Ergebnis zuverlässiger ist (keine Unterschiede zwischen Leopard und Snow Leopard).

Die Scripting Addition ist gratis und das Installieren ist rasch gemacht. Dann kann man sie vergessen ...

Sobald ich etwas mehr Luft habe, werde ich dennoch versuchen, eine do-shell-Script-Lösung zu liefern. Aber ich befürchte, dass mir da ein Mehrwissender zuvorkommen wird. :-)

Gruss, Hans


als Antwort auf: [#450949]

Datumskandidaten herausfiltern

michael m.
Beiträge gesamt: 162

29. Sep 2010, 09:03
Beitrag # 4 von 27
Beitrag ID: #452682
Bewertung:
(5451 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Hans,

Das Skript arbeitet schon mal aber leider nicht zuverlässig.
Jetzt ist es an der Zeit den Datum Suche Handler zu überabeiten.

von 167 Dateien wurden 30 Dateien mit Text in der Datei erkannt aber ohne ein Datum. Beim überprüfen der Dateien wurden in allen Dateien korrekte Datumsangaben gefunden.

also mein Algorithmus funktioniert zwar aber nicht zu 100 Prozent.
Jetzt ist es an der Zeit das Zusatzpacket zu installieren und Deine optimierte Variante zu Studieren und einzupflegen.

Da es sich hierbei um einen Handler handelt, muss ich nicht den kompletten Code durcharbeiten.

Ist mal wieder ein Vorteil, Code Stücke in Handler zu unterteilen.

Das ist aber noch nicht alles.
Damit ich auch das Skripten vertiefen kann muss ich den Datum Handler erweitern um weitere Datumsangaben zu finden wie:

12/03/2010
12/03/10

12-03-10
12-03-2010

12 März 2010
12. März 2010
12 März 10

12 Mar 2010
12. Mar 2010
12 Mar 10

Dann werde ich die restlichen Dateien damit prüfen und sehen was passiert.

Dein Beispiel aus dem ersten Post habe ich mal laufen lassen und mit Deinem Ergebnis kontrolliert.

Es stimmt überein:
Das Ergebnis des obenstehenden Beispiels: {"123.08.69", "03.04.2010", "12.10.02"}

aber es wäre noch ein Datum das real sein könnte und zwar das vom 18.8.04. Manche schreiben in Ihrer Korrekspondenz mit nullen 18.08.04 und manche auch nur 18.8.04.

So ich setze mich jetzt dran und versuche zu verstehen wie das ziemlich Kryptische aussehende Script funktioniert.


Viele Grüsse
Michael


als Antwort auf: [#450980]
(Dieser Beitrag wurde von michael m. am 29. Sep 2010, 09:17 geändert)

Datumskandidaten herausfiltern

michael m.
Beiträge gesamt: 162

29. Sep 2010, 09:40
Beitrag # 5 von 27
Beitrag ID: #452689
Bewertung:
(5437 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
So ich habe jetzt die es ausprobiert und auch folgende Frage:

Code
set punktListe to (find text "[0-9]{2,}\\.[0-9]{1,2}\\.[0-9]{2,4}" in textBlock with regexp, all occurrences and string result) 


gibt das Ergebnis

Code
{"123.08.69", "03.04.2010", "18.8.04", "12.10.02"} 


das aber 123.08.69 niemals ein mögliches Datum würde habe ich den Code wie folgt geändert.

Code
set punktListe to (find text "[0-9]{2}\\.[0-9]{1,2}\\.[0-9]{2,4}" in textBlock with regexp, all occurrences and string result) 


Wenn ich das richtig verstehe, dann dürfte das unmögliche Datum 123.08.69 nicht mehr mit berücksichtigt werden.

Es wird einfach die 1 abgeschnitten und daraus folgendes Ergbnis.

Code
 {"23.08.69", "03.04.2010", "18.8.04", "12.10.02"} 


Warum wird es denn abgeschnitten. Ich dachte es wird gefiltert.

Ich kann nicht erkennen, das es sich hier um eine länge von 8 oder 10 Zeichen eines möglichen Datums festgelegt wurde.

Ich suche nur nach Daten die eine Schema haben wie
1 Stelle 1 oder 2 Zeichen
2 Stelle 1 oder 2 Zeichen
3 Stelle 2 oder 4 Zeichen

Mit folgenden Code sollte das genau so definiert sein
Wenn die erste Stelle schon 3 Zeichen hat sollte es nicht in der punktListe sein.

Code
set punktListe to (find text "[0-9]{1,2}\\.[0-9]{1,2}\\.[0-9]{2,4}" in textBlock with regexp, all occurrences and string result) 


Erste Stelle eine oder 2 Zeichen
zweite Stelle eine oder 2 Zeichen
dritte Stelle 2 oder 4 Zeichen

Das Ergebnis ist:

Code
{"23.08.69", "03.04.2010", "8.09.210", "18.8.04", "12.10.02", "2.34.56"} 


Also nicht gerade das was ich mir erhofft hatte.

Code
find text "[0-9]{1-2}\\.[0-9]{1-2}\\.[0-9]{2,4}" 


Kommt auch nicht an das gewünschte Ergebnis heran. Die List ist damit leer.

Viele Grüsse

Michael


als Antwort auf: [#452682]
(Dieser Beitrag wurde von michael m. am 29. Sep 2010, 10:01 geändert)

Datumskandidaten herausfiltern

Hans Haesler
  
Beiträge gesamt: 5826

29. Sep 2010, 10:06
Beitrag # 6 von 27
Beitrag ID: #452693
Bewertung:
(5428 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Michael,

gegen Ende meines Beitrags hatte ich davor gewarnt:

Zitat Nur die Gruppe in der Mitte darf auf zwei Stellen fixiert werden. Bei der ersten und der letzten muss man alle vorhandenen aufnehmen. Sonst könnte bei einer Beschränkung auf ebenfalls je zwei aus dem Beispiel 123.12.456 das gültige Datum 23.12.45 werden.

Weil es unmöglich ist, nur gültige Daten auf einen Schlag herauszufiltern, muss das Ausscheiden in einem zweiten Schritt geschehen:

Zitat Die restlichen werden in einem weiteren Abschnitt untersucht und behalten, falls sie die Kriterien (Tag = 2 Stellen, zwischen 1 und 31; Monat = 2 Stellen, zwischen 1 und 12; Jahr = 2 oder 4 Stellen) erfüllen.

Gruss, Hans


als Antwort auf: [#452689]

Datumskandidaten herausfiltern

TMA
Beiträge gesamt: 399

29. Sep 2010, 10:06
Beitrag # 7 von 27
Beitrag ID: #452694
Bewertung:
(5426 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Michael,
klar das der das so findet.
Du musst dem Ausdruck noch sagen das vor den ersten 2-stelligen Ziffern die du suchst keine Zahl vorkommen darf.
Das macht man so [^0-9]. Das Dach in eckigen Klammern besagt das dieses nicht zutreffen soll.

Deine Zeile müsste dann so aussehen:
Code
set punktListe to (find text "[^0-9][0-9]{2}\\.[0-9]{1,2}\\.[0-9]{2,4}" in textBlock with regexp, all occurrences and string result) 


Gruß
TMA


als Antwort auf: [#452689]

Datumskandidaten herausfiltern

michael m.
Beiträge gesamt: 162

29. Sep 2010, 10:35
Beitrag # 8 von 27
Beitrag ID: #452698
Bewertung:
(5408 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo,

so wie ich das verstanden habe, kann ich also mit dem Baustein Filtern.
OK.
Soweit so gut.
Das mit dem Dach habe ich auch verstanden.

find text "[^0-9][0-9]{2}\\.[0-9]{1,2}\\.[0-9]{2,4}"

-- Anfang erste Stelle

Hier wird also die Eckige Klammer mit dem Dach für die erste Stelle definiert die zweite Eckige Klammer die Stellen zwei und drei WEIL in der geschwungenen Klammer eine 2 für 2 Stelllen steht.

-- Ende erste Stelle

Also das verstehe ich schon wie Ihr mir das erklärt aber ich verstehe hier keine Logik.

Wenn ich das hier schreibe jetzt nur mal für die erste Stelle

find text "[0-9]{2}\\.

Heisst, das die erste Stelle 2 Zahlen von 0-9 enthalten darf.

Warum schneidet er ab und ignoriert nicht einfach die dreistellige Zahl.
Das ist warum ich das nicht verstehe.

Das davor von eine Klammer mich Dach stehen muss OK ich kenne den Befehl nicht so ausführlich aber dann verstehe ich nicht warum in den geschweiften Klammer für die Begrenzung steht?
Wird hier beschnitten auf ein Muster oder wirklich gefiltert.
Irgendwo fehlt mir dazu die Logic um das ganze zu verstehen.

Wenn aus 123 eine 23 wird dann ist das eine Manilpulation der Zahl aber nicht gefiltert.


Viele Grüsse

Michael


als Antwort auf: [#452694]

Datumskandidaten herausfiltern

TMA
Beiträge gesamt: 399

29. Sep 2010, 10:50
Beitrag # 9 von 27
Beitrag ID: #452700
Bewertung:
(5406 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hi Michael,
also der Befehl "find text" heisst ja nicht umsonst so. Er soll also was finden.

Und da "123" nunmal auch 2 Ziffern enthält, findet er diese auch.

Beispiel, probier mal aus:
Code
find text "[0-9]{2}" in "1234" with regexp, all occurrences and string result 

findet "12" und "34".

Wobei:
Code
find text "[0-9]{2}" in "123" with regexp, all occurrences and string result 

logischerweise nur "12" findet.

Gruß
TMA


als Antwort auf: [#452698]

Datumskandidaten herausfiltern

michael m.
Beiträge gesamt: 162

29. Sep 2010, 11:23
Beitrag # 10 von 27
Beitrag ID: #452707
Bewertung:
(5391 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo TMA,

vielen Dank für die ausführliche Erläuterung.
Das leuchtet ein.
Also wenn ich zur Zeit nicht so abgespannt wäre hatte ich selbst auf find text kommen müssen, das damit finden gemeint ist.

Jetzt verstehe ich auch warum man dann auch 2 Durchgänge benötigt um ein reales Datum zu finden.

Viele Grüsse
Michael


als Antwort auf: [#452700]

Datumskandidaten herausfiltern

Hans Haesler
  
Beiträge gesamt: 5826

29. Sep 2010, 11:35
Beitrag # 11 von 27
Beitrag ID: #452711
Bewertung:
(5380 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo TMA und Michael,

das Teil [^0-9] ist für diese Aufgabe ungeeignet.

Okay, das Beispiel 123.08.69 erscheint nicht mehr im Ergebnis. Aber dafür werden die beiden anderen je mit einem führenden Leerschlag versehen.

In einem echten Text könnte anstelle des Leerschlags auch eine Klammer oder sonst ein Zeichen stehen.

Deshalb: Lieber den Befehl so einsetzen, wie ich ihn im ersten Beitrag zusammengesetzt hatte.

Damals war nur von Daten im Format DD.MM.YY oder DD.MM.YYYY die Rede. Wenn nun auch DD.M.YY gefunden werden soll, dann ist {1,2} in Ordnung.

Aber das Begrenzen der Jahrzahl mit {2,4} sollte unterlassen werden, weil dadurch Zahlen verfälscht werden können.

Gruss, Hans


als Antwort auf: [#452707]

Datumskandidaten herausfiltern

TMA
Beiträge gesamt: 399

29. Sep 2010, 11:46
Beitrag # 12 von 27
Beitrag ID: #452714
Bewertung:
(5374 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Hans,
ja das hängt immer davon ab, was für ein Text durchsucht werden muss. Den kennen wir ja leider nicht ganz.

Trotzdem möchte ich noch auf diese Variante verweisen:
Code
set textBlock to "Test 123.08.69 und 03.04.2010 sowie 8.09.210 oder 18.8.04 und 12.10.02 oder auch 2.34.56" 

try
set punktListe to (find text "[^[[:alnum:]]]([0-9]{2}\\.[0-9]{1,2}\\.[0-9]{2,4})" in textBlock using "\\1" with regexp, all occurrences and string result)
on error
set punktListe to {}
end try


Somit sind auch die Leerzeichen weg und falls vorhanden noch Buchstaben oder Ziffern davor.

Es kommt ja nur die gefundene Gruppe zurück.

Gruß
TMA


als Antwort auf: [#452711]

Datumskandidaten herausfiltern

michael m.
Beiträge gesamt: 162

29. Sep 2010, 12:13
Beitrag # 13 von 27
Beitrag ID: #452719
Bewertung:
(5362 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Hans,

in meinem Testlauf mit 167 Dateien habe ich sogar Dateien gefunden die meist die führende null nicht berücksichtigen wie.

D.M.YY oder D.M.YYYY

jetzt stellt sich die Frage

{1,2}

bedeutet das eine stelle und (oder) zweistellen?

In wie weit können Daten verfälscht werden wenn man für
die Jahreszahl {2,4} definiert.
Wenn die Jahreszahl 2 stellig ist und (oder) 4 stellig ist wäre das doch nicht flasch?
eine 3 Stelliges Datum gibt es ja nicht.

Viele Grüsse
Michael


als Antwort auf: [#452711]

Datumskandidaten herausfiltern

TMA
Beiträge gesamt: 399

29. Sep 2010, 12:23
Beitrag # 14 von 27
Beitrag ID: #452721
Bewertung:
(5360 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo Michael,
{2} = genau 2x
{1,2} = min. 1x, max. 2x (also 1. Wert ist min., 2. Wert ist max.)
{2,} = min. 2x oder öfter

{2,4} ist demnach nicht falsch wenn es keine 3-stelligen gibt.

Gruß
TMA


als Antwort auf: [#452719]

Datumskandidaten herausfiltern

Hans Haesler
  
Beiträge gesamt: 5826

29. Sep 2010, 12:23
Beitrag # 15 von 27
Beitrag ID: #452722
Bewertung:
(5359 mal gelesen)
URL zum Beitrag
Beitrag als Lesezeichen
Hallo TMA,

Du bist mir zuvorgekommen. :-) Nachstehend dennoch meine Ergänzung.

Es gibt zwar eine Möglichkeit, die überlüssigen Leerschläge usw. loszuwerden. Dazu definiert man den korrekten Teil des Suchmusters als Gruppe, indem man ihn mit runden Klammern einfasst. Und mit using \\1 pflückt man diese Gruppe heraus.

Code
set punktListe to (find text "[^0-9]?([0-9]{2}\\.[0-9]{1,2}\\.[0-9]{2,4})[^0-9]?" in textBlock using "\\1" with regexp, all occurrences and string result) 

Hier ist die Begrenzung auf vier Jahreszahl-Stellen beibehalten. Das bedingt aber auch ein weiteres Nicht-Zahl-Zeichen.

Die Fragezeichen hinter den beiden Nicht-Zahl-Zeichen sind notwendig. Es bedeutet: Dieses Zeichen kann vorhanden sein oder auch nicht. Sonst würde ein korrektes Datum zu Beginn (oder am Ende) der Textkette nicht im Ergebnis auftauchen.

Mit der Begrenzung der Jahreszahl auf vier Stellen kann man nicht verhindern, dass dreistellige durchkommen. Weil auf jeden Fall in der Folge die Gültigkeit geprüft werden muss, könnte auf das Begrenzen verzichtet werden.

Gruss, Hans


als Antwort auf: [#452714]
X