regex zum ersetzen eines Textmusters gesucht

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
blutigeranfaenger
User
Beiträge: 65
Registriert: Dienstag 4. März 2014, 12:04

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".
nezzcarth
User
Beiträge: 1651
Registriert: Samstag 16. April 2011, 12:47

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.
blutigeranfaenger
User
Beiträge: 65
Registriert: Dienstag 4. März 2014, 12:04

Ja, das ist Lilypond. Aber was meinst Du mit "Nimm einen geeigneten Parser"?
Benutzeravatar
pillmuncher
User
Beiträge: 1490
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

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.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
grubenfox
User
Beiträge: 454
Registriert: Freitag 2. Dezember 2022, 15:49

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).
Benutzeravatar
__blackjack__
User
Beiträge: 13271
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

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]>]
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
Antworten