Seite 1 von 1
regex zum ersetzen eines Textmusters gesucht
Verfasst: Samstag 25. Mai 2024, 16:02
von blutigeranfaenger
Hallo zusammen,
ich möchte gerne aus unten stehendem Text folgendes Muster komplett entfernen:
\mark \markup { \box { BUCHSTABE } }
wobei Buchtabe für einen Großbuchstaben A-Z steht.
Ich habe es mit folgendem Skript probiert:
Code: Alles auswählen
#!/usr/bin/env python3
import re
text = """
\version "2.22.2"
violine = {
\clef "treble" | % 1
R1*8 | % 9
\mark \markup { \box { A } } R1*8 -\markup{ \tiny {Lija+Tambor} }
\mark \markup { \box { B } }
R1*8
\mark \markup { \box { C } }
r4 <f'' b''>2. \fermata :32
}
"""
# Regex-Muster zum Finden und Entfernen der gewünschten Elemente
pattern = r'\\mark\s+\\markup\s+\{\s*\\box\s*\{\s*[A-Z]\s*\}\s*\}'
# Entfernen der gefundenen Elemente
cleaned_text = re.sub(pattern, '', text)
# Ausgabe des bereinigten Textes
print(cleaned_text)
Leider funkioniert das aber nicht wie gewünscht! Es erscheint z.B.
\mark \markup {ox { A } }
und aus "\fermata" wird "ermata".
Re: regex zum ersetzen eines Textmusters gesucht
Verfasst: Samstag 25. Mai 2024, 16:38
von nezzcarth
Das ist lilypond oder? Nimm einen geeigneten Parser. Mit normalen regulären Ausdrücken (alleine) wird das nur unstabiles Gefummel, u.a. da sie nicht für das korrekte Matchen von Klammerausdrücken geeignet sind (Ausnahme ist z.B. das externe Luapat, das aber eine sehr spezielle Variante von regex ist und ebenfalls ein externes Paket). Abgesehen davon muss in 'text' escaped oder ein raw string verwendet werden.
Re: regex zum ersetzen eines Textmusters gesucht
Verfasst: Samstag 25. Mai 2024, 17:12
von blutigeranfaenger
Ja, das ist Lilypond. Aber was meinst Du mit "Nimm einen geeigneten Parser"?
Re: regex zum ersetzen eines Textmusters gesucht
Verfasst: Samstag 25. Mai 2024, 19:24
von pillmuncher
blutigeranfaenger hat geschrieben: Samstag 25. Mai 2024, 17:12
Ja, das ist Lilypond. Aber was meinst Du mit "Nimm einen geeigneten Parser"?
Parsen bedeutet, einen Text in grammatisch bedeutungsvolle Teile zu zerlegen. "Teile" auf Lateinisch heißt "partes", davon abgeleitet ist ein Programm, das das erledigt, ein Parser. Wenn man einen Text parsen will, braucht man die dazugehörende Grammatik. Hier ist die von Lilypond:
http://lilypond.web.fc2.com/v2.13.45/Do ... ammar.html
Leider scheint es für Lilypond nur fertige Parser in Scheme zu geben, für Python habe ich nach kurzem googlen nichts gefunden. Vielleicht hast du ja mehr Glück. Ansonsten, wenn du das in Python bauen willst, solltest du eine bestehende Parser-Bibliothek verwenden, am Besten eine, die es erlaubt, die syntaktischen Regeln ("die Grammatik") in der Form zu programmieren, wie in dem o.s. Link. Ich mag ja gerne Parserkombinatoren, wo man das direkt in Python schreiben kann, statt in einer extra Sprache wie yacc. Schau dir mal
PyParsing oder
Parsy an.
Re: regex zum ersetzen eines Textmusters gesucht
Verfasst: Samstag 25. Mai 2024, 23:29
von grubenfox
Mich hat die Suche nach
https://github.com/frescobaldi/python-ly und
https://github.com/frescobaldi/quickly geführt. Mit beiden kann man offenbar Lilypond-Dateien bearbeiten.
Beim letzten gibt es noch einen Link nach
https://parce.info/... (und das ist was zum Thema Parsing völlig unabhängig von Lilypond).
Re: regex zum ersetzen eines Textmusters gesucht
Verfasst: Sonntag 26. Mai 2024, 15:46
von __blackjack__
Habe mir `parce` mal angeschaut und wie man damit die entsprechenden Textstellen finden kann:
Code: Alles auswählen
#!/usr/bin/env python3
from functools import partial
import parce
from parce.lang.lilypond import LilyPond
SOURCE_TEXT = R"""
\version "2.22.2"
violine = {
\clef "treble" | % 1
R1*8 | % 9
\mark \markup { \box { A } } R1*8 -\markup{ \tiny {Lija+Tambor} }
\mark \markup { \box { B } }
R1*8
\mark \markup { \box { C } }
r4 <f'' b''>2. \fermata :32
}
"""
parse = partial(parce.root, LilyPond.root)
PATTERN_TOKENS = list(parse(R"\mark \markup { \box { SOME_TEXT } }").tokens())
def find_all(node, pattern_tokens):
first_pattern_token, *pattern_tokens = pattern_tokens
for start_token in node.query.all(
first_pattern_token.text, first_pattern_token.action
):
query = start_token.query
for pattern_token in pattern_tokens:
query = (
query.next.action(pattern_token.action)
if pattern_token.text == "SOME_TEXT"
else query.next(pattern_token.text, pattern_token.action)
)
end_token = query.pick()
if end_token is not None:
yield start_token.range(end_token)
def main():
tree = parse(SOURCE_TEXT)
tree.dump()
print(list(find_all(tree, PATTERN_TOKENS)))
if __name__ == "__main__":
main()
Ausgabe:
Code: Alles auswählen
<Context LilyPond.root at 1-266 (5 children)>
├╴<Token '\\version' at 1:9 (Keyword)>
├╴<Context LilyPond.list at 10-18 (1 child)>
│ ╰╴<Context LilyPond.string at 10-18 (3 children)>
│ ├╴<Token '"' at 10:11 (Literal.String)>
│ ├╴<Token '2.22.2' at 11:17 (Literal.String)>
│ ╰╴<Token '"' at 17:18 (Literal.String)>
├╴<Context LilyPond.list at 20-27 (1 child)>
│ ╰╴<Token 'violine' at 20:27 (Name.Variable.Definition)>
├╴<Token '=' at 28:29 (Delimiter.Operator.Assignment)>
╰╴<Context LilyPond.musiclist* at 31-266 (37 children)>
├╴<Token '{' at 31:32 (Delimiter.Bracket.Start)>
├╴<Token '\\clef' at 37:42 (Name.Builtin)>
├╴<Context LilyPond.list at 43-51 (1 child)>
│ ╰╴<Context LilyPond.string at 43-51 (3 children)>
│ ├╴<Token '"' at 43:44 (Literal.String)>
│ ├╴<Token 'treble' at 44:50 (Literal.String)>
│ ╰╴<Token '"' at 50:51 (Literal.String)>
├╴<Token '|' at 52:53 (Delimiter.Separator.PipeSymbol)>
├╴<Context LilyPond.singleline_comment at 54-57 (2 children)>
│ ├╴<Token '%' at 54:55 (Comment)>
│ ╰╴<Token ' 1' at 55:57 (Comment)>
├╴<Token 'R' at 62:63 (Text.Music.Rest)>
├╴<Token '1' at 63:64 (Literal.Number.Duration)>
├╴<Context LilyPond.duration at 64-66 (1 child)>
│ ╰╴<Context LilyPond.duration_scaling at 64-66 (2 children)>
│ ├╴<Token '*' at 64:65 (Literal.Number.Duration)>
│ ╰╴<Token '8' at 65:66 (Literal.Number.Duration.Scaling)>
├╴<Token '|' at 67:68 (Delimiter.Separator.PipeSymbol)>
├╴<Context LilyPond.singleline_comment at 69-72 (2 children)>
│ ├╴<Token '%' at 69:70 (Comment)>
│ ╰╴<Token ' 9' at 70:72 (Comment)>
├╴<Token '\\mark' at 77:82 (Name.Builtin)>
├╴<Context LilyPond.markup at 83-90 (1 child)>
│ ╰╴<Token '\\markup' at 83:90 (Keyword.Markup)>
├╴<Context LilyPond.markuplist at 91-107 (4 children)>
│ ├╴<Token '{' at 91:92 (Delimiter.Bracket.Markup.Start)>
│ ├╴<Token '\\box' at 93:97 (Name.Function.Markup)>
│ ├╴<Context LilyPond.markuplist at 98-105 (3 children)>
│ │ ├╴<Token '{' at 98:99 (Delimiter.Bracket.Markup.Start)>
│ │ ├╴<Token 'A' at 100:101 (Text)>
│ │ ╰╴<Token '}' at 104:105 (Delimiter.Bracket.Markup.End)>
│ ╰╴<Token '}' at 106:107 (Delimiter.Bracket.Markup.End)>
├╴<Token 'R' at 108:109 (Text.Music.Rest)>
├╴<Token '1' at 109:110 (Literal.Number.Duration)>
├╴<Context LilyPond.duration at 110-112 (1 child)>
│ ╰╴<Context LilyPond.duration_scaling at 110-112 (2 children)>
│ ├╴<Token '*' at 110:111 (Literal.Number.Duration)>
│ ╰╴<Token '8' at 111:112 (Literal.Number.Duration.Scaling)>
├╴<Token '-' at 113:114 (Delimiter.Direction)>
├╴<Context LilyPond.markup at 114-121 (1 child)>
│ ╰╴<Token '\\markup' at 114:121 (Keyword.Markup)>
├╴<Context LilyPond.markuplist at 121-144 (4 children)>
│ ├╴<Token '{' at 121:122 (Delimiter.Bracket.Markup.Start)>
│ ├╴<Token '\\tiny' at 123:128 (Name.Function.Markup)>
│ ├╴<Context LilyPond.markuplist at 129-142 (3 children)>
│ │ ├╴<Token '{' at 129:130 (Delimiter.Bracket.Markup.Start)>
│ │ ├╴<Token 'Lija+Tambor' at 130:141 (Text)>
│ │ ╰╴<Token '}' at 141:142 (Delimiter.Bracket.Markup.End)>
│ ╰╴<Token '}' at 143:144 (Delimiter.Bracket.Markup.End)>
├╴<Token '\\mark' at 149:154 (Name.Builtin)>
├╴<Context LilyPond.markup at 155-162 (1 child)>
│ ╰╴<Token '\\markup' at 155:162 (Keyword.Markup)>
├╴<Context LilyPond.markuplist at 163-179 (4 children)>
│ ├╴<Token '{' at 163:164 (Delimiter.Bracket.Markup.Start)>
│ ├╴<Token '\\box' at 165:169 (Name.Function.Markup)>
│ ├╴<Context LilyPond.markuplist at 170-177 (3 children)>
│ │ ├╴<Token '{' at 170:171 (Delimiter.Bracket.Markup.Start)>
│ │ ├╴<Token 'B' at 172:173 (Text)>
│ │ ╰╴<Token '}' at 176:177 (Delimiter.Bracket.Markup.End)>
│ ╰╴<Token '}' at 178:179 (Delimiter.Bracket.Markup.End)>
├╴<Token 'R' at 186:187 (Text.Music.Rest)>
├╴<Token '1' at 187:188 (Literal.Number.Duration)>
├╴<Context LilyPond.duration at 188-190 (1 child)>
│ ╰╴<Context LilyPond.duration_scaling at 188-190 (2 children)>
│ ├╴<Token '*' at 188:189 (Literal.Number.Duration)>
│ ╰╴<Token '8' at 189:190 (Literal.Number.Duration.Scaling)>
├╴<Token '\\mark' at 196:201 (Name.Builtin)>
├╴<Context LilyPond.markup at 202-209 (1 child)>
│ ╰╴<Token '\\markup' at 202:209 (Keyword.Markup)>
├╴<Context LilyPond.markuplist at 210-226 (4 children)>
│ ├╴<Token '{' at 210:211 (Delimiter.Bracket.Markup.Start)>
│ ├╴<Token '\\box' at 212:216 (Name.Function.Markup)>
│ ├╴<Context LilyPond.markuplist at 217-224 (3 children)>
│ │ ├╴<Token '{' at 217:218 (Delimiter.Bracket.Markup.Start)>
│ │ ├╴<Token 'C' at 219:220 (Text)>
│ │ ╰╴<Token '}' at 223:224 (Delimiter.Bracket.Markup.End)>
│ ╰╴<Token '}' at 225:226 (Delimiter.Bracket.Markup.End)>
├╴<Token 'r' at 232:233 (Text.Music.Rest)>
├╴<Token '4' at 233:234 (Literal.Number.Duration)>
├╴<Context LilyPond.chord at 235-244 (6 children)>
│ ├╴<Token '<' at 235:236 (Delimiter.Chord.Start)>
│ ├╴<Token 'f' at 236:237 (Text.Music.Pitch)>
│ ├╴<Context LilyPond.pitch at 237-239 (1 child)>
│ │ ╰╴<Token "''" at 237:239 (Text.Music.Pitch.Octave)>
│ ├╴<Token 'b' at 240:241 (Text.Music.Pitch)>
│ ├╴<Context LilyPond.pitch at 241-243 (1 child)>
│ │ ╰╴<Token "''" at 241:243 (Text.Music.Pitch.Octave)>
│ ╰╴<Token '>' at 243:244 (Delimiter.Chord.End)>
├╴<Token '2' at 244:245 (Literal.Number.Duration)>
├╴<Context LilyPond.duration at 245-246 (1 child)>
│ ╰╴<Token '.' at 245:246 (Literal.Number.Duration.Dot)>
├╴<Token '\\fermata' at 247:255 (Name.Script.Articulation)>
├╴<Token ':' at 256:257 (Delimiter.Tremolo)>
├╴<Token '32' at 257:259 (Literal.Number.Duration.Tremolo)>
╰╴<Token '}' at 265:266 (Delimiter.Bracket.End)>
[<Range LilyPond.musiclist* [77:107]>, <Range LilyPond.musiclist* [149:179]>, <Range LilyPond.musiclist* [196:226]>]