[regex] Ziffernfolge am Zeilenende

amn.ssy

Erfahrenes Mitglied
Guten Morgen,

ich habe übers WE auf regexe.de einen Pattern gebastelt, der leider nur dort so funktioniert wie er soll. Im VBS leider nicht, was aber auch am Einlesen der Textdatei liegen kann (Array?).
In besagter Textdatei beginnt jede Zeile mit einem "Wort" und endet i.d.R. mit einer Ziffernfolge. Die Ziffernfolge kann aus einer einstelligen Ganzzahl (0,1,...) oder aus einer Dezimalzahl mit max. zwei Nachkommastellen bestehen (Komma = Punkt, z.B. 100.23).

Beispiel:
Code:
Units tested                                      Min. 10                                                               10
Lowest value                                      Min. 25                             N                                 78
Average mass                                      220 to 244                          mg                               227
Portion (>7,5%<=15%)                              Max. 10                             %                                  0
Portion (>15%)                                    Max. 0                              %                                  0
Units tested                                      Min. 6                                                                  6
Mean value                                        Min. 80                             % decl. content                    99
Lowest value                                                                          % decl. content                    97
Highest value                                                                         % decl. content                  101
Manufacturing date: 12 Jun 2012

Versucht habe ich es hiermit:
Code:
    .Pattern = "([a-zA-Z]+\s+[a-zA-Z]+\b)(?:\(?.*\)?.*)(\b\d+\.?\d)"
    T =.Replace(T, "$1;$2")

Mit diesem Ziel:
Code:
Units tested;10
Lowest value;78
Average mass;227
Portion;0
Portion;0
Units tested;6
Mean value;99
Lowest value;97
Highest value;101
Manufacturing date; 12 Jun 2012

Unter besagtem Onlinetool funktioniert das weitgehenst mit den Ausnahmen, daß einstellige Ganzzahlen oder Dezimalzahlen mit mehr als einer Nachkommastelle nicht erkannt werden.
Ein "kleiner" Schönheitsfehler besteht auch darin, daß am Zeilenanfang auch mal nur ein Wort stehen kann bzw. das Datum unbehelligt bleiben soll.
Wie kann ich das realisieren, vor allem im VBS, denn da läuft es nämlich nicht?

Das Ganze VBS sieht zum Testen derzeit so aus, min. die auskommentierten Stellen könnten idealerweise entfallen:

Code:
InFile = WScript.Arguments(0)
OutFile = WScript.Arguments(1)

Set fso = CreateObject("Scripting.FileSystemObject")
If fso.GetFile(InFile).Size = 0 Then
    fso.CreateTextFile(OutFile)
    WScript.Quit
End If
T = fso.OpenTextFile(WScript.Arguments(0)).ReadAll

With New RegExp

	.Global = True
	.IgnoreCase = True
	.Multiline = True
    	
    
    .Pattern = "[ ]{2,}"
    T = .Replace(T, " ")

    .Pattern = "(Quantity :)"
   T = .Replace(T, "")

    '.Pattern = "(:)"
    'T = .Replace(T, ";")

    '.Pattern = "(Batch No)\s+(\d)"
    'T = .Replace(T, "$1;$2")

    '.Pattern = "(tested|value|mass) "
    'T = .Replace(T, "$1 ; ")
    	
    '.Pattern = " (\d)"
    'T =.Replace(T, " ; $1")
	
    .Pattern = "([a-zA-Z]+\s+[a-zA-Z]+\b)(?:\(?.*\)?.*)(\b\d+\.?\d)"
    T =.Replace(T, "$1;$2")

End With

Weil ich beim "stöbern" schon mehrfach über "sed" gestolpert bin: Läßt sich das Problem damit besser lösen? Wo finde ich das Programm mit mehr oder minder guter Dokumentation\Hilfe?


LG
_opiwahn_
 
Zuletzt bearbeitet:
sed? noch nie gewohnt.
Vergiss regexe.de zum Patterns für VBS zu erstellen. Die Seite mag gut für irgend eine Sprache sein, aber Regexp von VBS kennt nicht so viele Befehle. Schreib dir selber ein Testcode.

Ich komme da auf so etwas
Visual Basic:
    RegExp.Multiline = True
    RegExp.Global = True
    
    'Datum im Format "31 Jan 2013"
    Const C_DATE_PATTERN = "(?:0[1-9]|[1-2][0-9]|3[01]) (?:Jan|Feb|Mar|Apr |May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) 20[\d]{2}"
    
    RegExp.Pattern = "^(?:(.*" & C_DATE_PATTERN & ")|((?:[a-zA-Z]+|[ ]{1}[^ ])+).*(?:[^\d\.])([\d\.]+))$"
    txt = RegExp.Replace(txt, "$1$2;$3")
    'Bei der Datumszeile hat es am Ende noch ein ; durch den verherigen replace. DIesen noch entfernen
    RegExp.Pattern = "^(.*)[^;];?$"
    txt = RegExp.Replace(txt, "$1")

Das Pattern ist so aufgebaut:
Code:
-- netweder ist die komplette Zeile nach dem Muster
(.*" & C_DATE_PATTERN & ")
-- Also von Zeilenanfang an irgendwas, gefolgt von einem Datum
-- DIes ist die ersate KLammer und somit $1

-- oder sie ist so aufgebaut
((?:[a-zA-Z]+|[ ]{1}[^ ])+).*(?:[^\d\.])([\d\.]+))
-- Wobei der Zeilenanfang Buchstaben und einzelne Leerzeichen zulässt, nicht jedoch Leerzeichen hintereinander. (Zweite Klammer -> $2)
-- gefolgt von alle möglichen.
-- Das Zeilenende beseht aus mindestens einer Ziffer.
-- davor können noch Ziffern und Punkte kommen
-- Das Zeilenende ist die dritte Klammer -> $3
 
Mallo Yaslaw,

ich sag mal vorab - ungetestet - Danke.
Sieht gut und einleuchtend aus (bei der Erklärung :))
Mir scheint ich hab den "Dampfer" zumindest aus der Nähe gesehen ;-)

gruß
_opiwahn_
 
Hallo Yaslaw,

nochmals Danke, das geht schon schwer in die richtige Richtung.

Ich habe das jetzt so umgesetzt
Visual Basic:
InFile = WScript.Arguments(0)
OutFile = WScript.Arguments(1)

Set fso = CreateObject("Scripting.FileSystemObject")
If fso.GetFile(InFile).Size = 0 Then
    fso.CreateTextFile(OutFile)
    WScript.Quit
End If
T = fso.OpenTextFile(WScript.Arguments(0)).ReadAll

With New RegExp

	.Global = True
	.IgnoreCase = True
	.Multiline = True
    	
    Const C_DATE_PATTERN = "(?:0[1-9]|[1-2][0-9]|3[01]) (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) 20[\d]{2}"

    .Pattern = "[ ]{2,}"
    T = .Replace(T, " ")

    .Pattern = "(Quantity :|% decl. content|Min.)"
    T = .Replace(T, "")

    .Pattern = "(:)"
    T = .Replace(T, ";")

	
    .Pattern = "^(?:(.*" & C_DATE_PATTERN & ")|((?:[a-zA-Z]+|[ ]{1}[^ ])+).*(?:[^\d\.])([\d\.]+))$"
    T = .Replace(T, "$1$2;$3")

    .Pattern = "^(.*)[^;];?$"
    T = .Replace(T, "$1")

End With

fso.CreateTextFile(WScript.Arguments(1), True).Write(T)

mit diesem Ergebnis:

Code:
  Batch no. ; 156878D
 Units tested;10
 Lowest value;57
 Units tested;20
 Average mass 2;224
 Portion (;0
 Portion (;0
 Mean value 9;99
 Units tested;6
 Mean value;98
 Lowest value;97
 Highest value;100
  Batch no. ; 156878D
 Manufacturing date; 04 Jan 2012;
 Manufacturing Date;2012

Auffällig sind die Zeilen 5 - 8 wo noch was mitgenommen wird was da nicht hin soll.
Zuvor war auch noch "Min." in den Zeilen 2-5 und 9,10 mit drin.
Das hab ich mit dem 2. Replace raus geholt.
Beim letzen Semikolon muß ich wohl was falsch verstanden haben.
Jedenfalls bleibt's wohl erhalten, was aber bei einer CSV wohl nicht so dramatisch ist.

Gibt es eine "einfache" Möglichkeit die letzte Zeile zu löschen, da sie eh' doppelt ist (wie Batch auch)?
Bei meiner Dateiliste kann ich das in einem Zwischenschritt schön mit "sort -u" aus den GNU-Tools erledigen, da die Reihenfolge in den weiteren Schritten nicht wichtig ist.
In diesem jeweiligen Output kann ich aber nicht sortieren, da die Reihenfolge erhalten bleiben muß.

Ich habe mit heute mittag gerade gedacht, daß wenn in "InFile" ja mein Dateinamen steht, konnte ich ja mit if ... else oder select case auf die einzelnen speziellen "Verfahren" verweisen und ansonsten allgemein gültig behandeln.
Außerdem müßte ich (evt. zu Lasten der Übersichlichkeit) nicht für jedes "Produkt" eine eigenes VBS anlegen, sondern das eine nur mit jeder neuen Anforderung erweitern.

Gruß
_opiwahn_
 
Zurück