regex asc file parsen

OP #7267469
Lesenswert?

Ich würde gerne mit Hilfe regulärer Ausdrücke

https://regex101.com/
https://quickref.me/regex

ein ASC-File parsen. Das File sieht so aus
1
SYMBOL voltage -128 160 R0
2
WINDOW 123 0 0 Left 2
3
WINDOW 39 0 0 Left 2
4
SYMATTR InstName V1
5
SYMATTR Value SINE(0 1 1000)
6
TEXT -160 408 Left 2 !.tran 5m
7
TEXT 296 272 Left 2 ;time
8
TEXT 688 256 VLeft 2 ;amplitude (vertical)
9
TEXT 216 16 Left 2 ;LtSpice Labels
10
TEXT 160 352 Left 2 ;Label  size 1.5
11
TEXT 160 408 Left 3 ;Label size 2.0
12
TEXT 160 480 Left 4 ;Label size 3.5
13
TEXT 152 544 Left 4 ;Label size 3.5
14
RECTANGLE Normal 880 784 80 -32 2

und ich will die Zeilen die mit "TEXT" beginnen und ein ";" haben 
finden.

Weis jemand, wie das geht?

Der erste Vorschlag wäre
1
^.*TEXT.*$

Dieser Ausdruck holt aber alle Zeilen, die "TEXT" enthalten, auch die 
ohne ";"
#7267516
Lesenswert?

Christoph M. schrieb:
> Dieser Ausdruck holt aber alle Zeilen, die "TEXT" enthalten, auch die
> ohne ";"

In dem Ausdruck kommt ja auch kein ";" vor.

Wilhelm M. schrieb:
> '^TEXT.*;'

Das matcht aber nicht auf die ganze Zeile, sondern nur auf den Teil bis 
zum Semikolon (einschließlich diesem).

Das hier matcht auf ganze Zeilen, die mit "TEXT" beginnen und irgendwo 
danach ein Semikolon enthalten:
1
^TEXT.*;.*$
Mit Capture-Groups könnte man noch die Bestandteile einzeln extrahieren.
OP #7267762
Lesenswert?

Rolf M. (rmagnus)

>Das hier matcht auf ganze Zeilen, die mit "TEXT" beginnen und irgendwo
>danach ein Semikolon enthalten:

>^TEXT.*;.*$

>Mit Capture-Groups könnte man noch die Bestandteile einzeln extrahieren.

Danke für den Code. Eigentlich brauche ich von der Zeile nur den Teil 
nach dem Semikolon. Gibt es da eine Möglichkeit, den Regex-Ausdruck zu 
kapseln und dann den Teil nach dem Semikolon zu extrahieren?
Gast #7269721
Lesenswert?

Ich würde da gar keine regex verwenden. Einfach passend splitten:
1
#!/bin/bash
2
while IFS=';' read sargs last
3
do
4
  set -o noglob
5
  args=( $sargs )
6
  set +o noglob
7
  if [ -n "$last" ]; then args+=("$last"); fi
8
  echo "Command: ${args[0]}"
9
  echo "Arguments:"
10
  printf " - %s\n" "${args[@]:1}"
11
done
OP #7271889
Lesenswert?

von 🐧 DPA 🐧 (Gast)
>Ich würde da gar keine regex verwenden. Einfach passend splitten:

Normalerweise mache ich es auch zu Fuß. Regex scheint recht mächtig, 
aber schwer nachzuvollziehen.
Ich wollte aber mal was neues ausprobieren, deshalb mal mit regex.
Das Ganze soll aber nicht in der bash sondern in Python verwendet 
werden.

TotoMitHarry (Gast)
>.. mit ?: wird die Klammer zwar auch gesucht, aber nicht ausgegeben ;)

Geht aber aber in folgendem Code nicht:
1
import re
2

3
txt = ""
4
txt = txt + "SYMBOL voltage -128 160 R0" +"\n"
5
txt = txt + "SYMATTR InstName V1" +"\n"
6
txt = txt + "SYMATTR Value SINE(0 1 1000)" +"\n"
7
txt = txt + "TEXT -160 408 Left 2 !.tran 5m" +"\n"
8
txt = txt + "TEXT 160 352 Left 2 ;Label  size 1.5"+"\n"
9
txt = txt + "TEXT 160 408 Left 3 ;Label size 2.0"+"\n"
10
txt = txt + "TEXT 160 480 Left 4 ;Label size 3.5"+"\n"
11
txt = txt + "TEXT 152 544 Left 4 ;Label size 3.5"+"\n"
12
txt = txt + "TEXT 688 256 VLeft 2 ;amplitude (vertical)"+"\n"
13
txt = txt + "RECTANGLE Normal 880 784 80 -32 2" +"\n"
14

15
x = re.findall(r"TEXT.*;(.*)", txt) # geht  
16
#x = re.findall(r"(?:^TEXT.*;)(.*)", txt) #geht nicht 
17

18
print(x)
19

20
for s in x:
21
  print(s)
Gast #7271954
Lesenswert?

1
#!/usr/bin/python3
2
# -*- coding: UTF-8 -*-
3

4
import re
5

6
data = '''
7
SYMBOL voltage -128 160 R0
8
WINDOW 123 0 0 Left 2
9
WINDOW 39 0 0 Left 2
10
SYMATTR InstName V1
11
SYMATTR Value SINE(0 1 1000)
12
TEXT -160 408 Left 2 !.tran 5m
13
TEXT 296 272 Left 2 ;time
14
TEXT 688 256 VLeft 2 ;amplitude (vertical)
15
TEXT 216 16 Left 2 ;LtSpice Labels
16
TEXT 160 352 Left 2 ;Label  size 1.5
17
TEXT 160 408 Left 3 ;Label size 2.0
18
TEXT 160 480 Left 4 ;Label size 3.5
19
TEXT 152 544 Left 4 ;Label size 3.5
20
RECTANGLE Normal 880 784 80 -32 2
21
'''
22

23
pattern = re.compile(r"^TEXT.*;(.*)")
24

25
for line in data.splitlines():
26
    result = pattern.match(line)
27
    if result:
28
        print(result.group(1))
1
time
2
amplitude (vertical)
3
LtSpice Labels
4
Label  size 1.5
5
Label size 2.0
6
Label size 3.5
7
Label size 3.5
OP #7273456
Lesenswert?

Danke dafür.
Jetzt habe ich schon das nächste Problem: Gesucht werden soll über 
mehrere Zeilen ..
1
Version 4
2
SHEET 1 948 804
3
WIRE -128 176 -128 128
4
WIRE -128 304 -128 256
5
FLAG -128 304 0
6
SYMBOL voltage -128 160 R0
7
WINDOW 123 0 0 Left 2
8
WINDOW 39 0 0 Left 2
9
SYMATTR InstName Spannung1
10
SYMATTR Value SINE(0 1 1000)
11
SYMBOL button 224 288 R0
12
SYMATTR InstName button1
13
SYMBOL button 224 336 R0
14
SYMATTR InstName button2
15
SYMBOL button 224 384 R0
16
SYMATTR InstName button3
17
TEXT -160 408 Left 2 !.tran 5m
18
TEXT 216 16 Left 2 ;LtSpice Labels
19
TEXT 224 232 Left 2 ;Selector
20
RECTANGLE Normal 880 784 80 -32 2

Die Definition eines Symbols verteilt sich über mehrere Zeilen (z.B. 2)
1
SYMBOL button 224 288 R0
2
SYMATTR InstName button1

Ich will den Namen "button1" aus den zwei Zeilen extrahieren. Das 
bedeutet also, man muss zuerst die Zeile mit dem Inhalt "SYMBOL button" 
und dann aus der Zeile mit "SYMATTR InstName" den Namen "button1" 
extrahieren.

Wenn ich als Regex-Expression folgendes nehme
1
(^SYMBOL button(.*)\nSYMATTR InstName).*
kommen als Matches immer beide Zeilen gleichzeitig, aber nicht der 
gesuchte Namen.
Gast #7273488
Lesenswert?

Python regex kann auch problemlos über mehrere Zeilen und man kann 
mehrere groups definieren.

Vielleicht ist noch nicht einmal garantiert, das die Zeilen immer in der 
von dir gewünschten Reihenfolge an die Tür klopfen.
Irgendwann wird es jedoch sinnvoller sein, eine kleine Klasse zu 
schreiben und etwas zusätzliche Logik zu implementieren.
Wer zu Klassen eine eher abweisende Grundeinstellung hat, nimmt dann 
eben closures.

All das zumal dieses aktuelle Problem wahrscheinlich nicht deine letzte 
Herausforderung sein wird.
OP #7273504
Lesenswert?

>Vielleicht ist noch nicht einmal garantiert, das die Zeilen immer in der
>von dir gewünschten Reihenfolge an die Tür klopfen.
>Irgendwann wird es jedoch sinnvoller sein, eine kleine Klasse zu
>schreiben und etwas zusätzliche Logik zu implementieren.

Vielleicht hast Du recht und ich sollte es vielleicht ohnehin ohne regex 
machen. Das ist für mich etwas eingängiger.

Das Format eine *.asc LtSpice Files ist etwas seltsam: Erst kommt die 
Symbolbezeichung und in den nachfolgenden Zeilen die Attribute. Alle 
Zeilen gehören dazu bis zur nächstmöglichen nächsten Symbolbezeichnung. 
Um die Endzeile eines Symbols zu erkennen muss man also erkennen das ein 
neues Symbol anfängt. Es können aber auch andere Elemente wie "TEXT" das 
Ende eines Symbols markieren. Ich weiß gar nicht, ob solch ein komplexer 
Parser mit Regex überhaupt möglich ist.

1
#!/usr/bin/python3
2
# -*- coding: UTF-8 -*-
3

4
import re
5

6
data = '''
7
Version 4
8
SHEET 1 948 804
9
WIRE -128 176 -128 128
10
WIRE -128 304 -128 256
11
FLAG -128 304 0
12
SYMBOL voltage -128 160 R0
13
WINDOW 123 0 0 Left 2
14
WINDOW 39 0 0 Left 2
15
SYMATTR InstName Spannung1
16
SYMATTR Value SINE(0 1 1000)
17
SYMBOL button 224 288 R0
18
SYMATTR InstName button1
19
SYMBOL button 224 336 R0
20
SYMATTR InstName button2
21
SYMBOL button 224 384 R0
22
SYMATTR InstName button3
23
TEXT -160 408 Left 2 !.tran 5m
24
TEXT 216 16 Left 2 ;LtSpice Labels
25
TEXT 224 232 Left 2 ;Selector
26
RECTANGLE Normal 880 784 80 -32 2
27
'''
28

29
pattern = re.compile(r"(^SYMBOL button(.*)\\nSYMATTR InstName)(.*)")
30
print(pattern.match(data))
Gast #7273515
Lesenswert?

Christoph M. schrieb:
> und ich sollte es vielleicht ohnehin ohne regex
> machen.

Gibt kaum etwas schöneres und flexibleres als RegEx.
Lies Zeilenweise ein, kompiliere dir verschiedene RegEx-Pattern, wende 
sie an und sammle die Ergebnisse. Wenn alle Zeilen eines Blocks gelesen 
sind, dann die Infos kombinieren.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren