Frage von Wissididom, 75

Problem beim SNG-Maker?

Ich habe einen SNG-Maker programmiert, der SNG-Dateien erstellen kann, ich habe nun noch ein Problem, dass ich bei einer Form besondere Worte farbig markieren will, was auch funktioniert, nun will ich aber nicht, dass z. B. Pre-Bridge bei Bridge eine andere Farbe hat als Pre-.

Hilfreichste Antwort - ausgezeichnet vom Fragesteller
von CrystalixXx, 30

So sieht es mit der Änderung bei mir aus.

Kommentar von Wissididom ,

Ja, das ist gut, aber ich will Pre-Bridge auch mit einer anderen Farbe markieren. Bei dem Teil Pre- hat es auch geklappt, beim Rest jedoch nicht und wenn eine Zahl nach einem Leerzeichen dahinter steht, soll sie mit markiert werden und wenn ein anderes Wort in der Zeile steht gar soll nichts markiert werden, ich hoffe ihr habt verstanden, was ich meine.

Kommentar von CrystalixXx ,

Deine Bedingungen sind nicht ganz klar. Ohne alle Einschränkungen zu kennen wird es unmöglich ein passendes Pattern zu finden.

  • "Bridge" soll nur markiert werden, wenn es am Zeilenanfang steht (Groß- und Kleinschreibung egal?)
  • "Bridge" soll nicht markiert werden, wenn daraufhin ein Wort folgt (sind Whitespace-Zeichen (Tab, Leerzeichen, ...) oder Sonderzeichen erlaubt?)
  • "Bridge" soll aber markiert werden, wenn daraufhin ein Leerzeichen und eine Zahl folgt (sind beliebig viele Leerzeichen erlaubt? Wie viele Ziffern darf die Zahl haben? Sind nach der Zahl Leerzeichen erlaubt?)

Ich habe jetzt ein Pattern, welches das Wort markiert, wenn es das

einzige Wort in der Zeile ist oder wenn es am Zeilenanfang steht und von beliebig vielen Whitespace-Zeichen und einer beliebig langen Zahl gefolgt wird:

Dim rPattern As String = "^" & word & "\s*\d*$"

Ist es vielleicht das, was du suchst? Wenn nach dem Wort "Bridge" nur höchstens ein Leerzeichen vorhanden sein darf, dann ersetzt du den Stern nach \s durch ein Fragezeichen. Wenn deine Zahl nur eine begrenzte Anzahl an Ziffern haben darf, dann ersetzt du den * durch {n,m} wobei n die Mindestanzahl und m die Höchstanzahl an Ziffern ist.

Kommentar von Wissididom ,
  • Zu deinen Punkten, Groß- Kleinschreibung soll ignoriert werden.
  • Sonderzeichen sind nicht erlaubt, und als Whitespace-Zeichen nur Leertaste, aber nicht zweimal Leertaste und wie du schon sagtest, wen danach Buchstaben folgen soll Bridge auch nicht markiert werden
  • Ein Leerzeichen ist wie gesagt erlaubt, aber keine 2 Leerzeichen
  • "Bridge " soll auch markiert werden
  • Die Zahl soll beliebig groß werden können, aber eine Ganzzahl sein
  • Nach der Zahl sind keine Leerzeichen erlaubt

Ich habe den Code der jetzt immer funktioniert hat auskommentiert und deinen Code eingegeben, aber es funktioniert nicht (siehe Bild auf pic-upload.de)
http://www.pic-upload.de/view-29865108/Screenshot_2.png.html

Kommentar von CrystalixXx ,

So, jetzt aber:

Dim rPattern As String = "^" & word & " ?\d*$"
Dim rOptions As RegexOptions = RegexOptions.IgnoreCase Or RegexOptions.Multiline

Groß- und Kleinschreibung wird durch Regexoptions ignoriert. Das Pattern erlaubt nur noch maximal ein Leerzeichen bis eine Ziffernfolge gefunden wird. "Bridge " wird ebenfalls markiert.

Wichtig für das Pattern ist außerdem die Option "Multiline", damit das Zirkumflex und Dollar-Zeichen für den Anfang respektive das Ende der Zeile stehen.

Kommentar von Wissididom ,

Jetzt geht es aber nur noch wenn weiter unten dasselbe ohne Zahl steht (siehe die 2 Bilder):

Kommentar von CrystalixXx ,

Mein Ergebnis: http://fs5.directupload.net/images/160228/qj9z4ngu.png

Kann es vielleicht sein, dass du noch anderen Code hast, der irgend etwas markiert oder Einfluss auf die RichTextBox nimmt? Ich sehe da nämlich bei dir noch eine andere Mark-Methode in deinem Screenshot.

Ansonsten wäre es interessant zu wissen, was dir folgende Codezeile anzeigt:

MessageBox.Show(regex.Matches(rtb.Text).Count.ToString)

Kopiere die Zeile vor die For Each Schleife. In meinem Beispiel wird "2" angezeigt. Das sollte bei dir theoretisch auch der Fall sein. Vielleicht hast du aber auch irgendwelche nicht druckbaren Zeichen in deinem Text? Du könntest daher mal die Textlänge überprüfen.

RichTextBox1.Text.Length

Bei mir werden "39" angezeigt.

Wenn das alles nichts hilft, dann weiß ich leider auch nicht weiter.

Kommentar von Wissididom ,

Hier der komplette Code der Form: http://www.mediafire.com/download/9u1pjijj1arfs2p/Form3.vb.txt

Das Mark_e markiert "---" rot, das funktioniert einwandfrei (Vordergrundfarbe)

Kommentar von CrystalixXx ,

Das Problem lag tatsächlich an deinem Code.

Private Sub RichTextBox1_TextChanged(sender As System.Object, e As System.EventArgs) Handles RichTextBox1.TextChanged
Dim pos As Integer = RichTextBox1.SelectionStart
Dim cat1 As String = "(Pre-(Bridge|Refrain|Chorus|Coda))"
Dim cat2 As String = "(Unbe(k|n)annt|Unknown)"
Dim cat3 As String = "(Intro|Coda|Ending)"
Dim cat4 As String = "(Verse?|Strophe|Teil|Part)"
Dim cat5 As String = "(Bridge|Misc|Zwischenspiel|Interlude)"
Dim cat6 As String = "(Refrain|Chorus)"

RichTextBox1.SelectAll()
RichTextBox1.SelectionBackColor = Color.White
RichTextBox1.SelectionColor = Color.Black

Call MarkWord(RichTextBox1, cat1, Color.FromArgb(170, 85, 255))
Call MarkWord(RichTextBox1, cat2, Color.FromArgb(98, 176, 255))
Call MarkWord(RichTextBox1, cat3, Color.FromArgb(0, 128, 64))
Call MarkWord(RichTextBox1, cat4, Color.FromArgb(0, 128, 255))
Call MarkWord(RichTextBox1, cat5, Color.FromArgb(204, 0, 0))
Call MarkWord(RichTextBox1, cat6, Color.FromArgb(128, 0, 255))
Call MarkLine(RichTextBox1, Color.FromArgb(255, 0, 0))

RichTextBox1.SelectionStart = pos
RichTextBox1.SelectionLength = 0
End Sub

Private Sub MarkWord(rtb As RichTextBox, word As String, bColor As Color)
Call Mark(rtb, "^" & word & " ?\d*$", bColor, Color.Black)
End Sub

Private Sub MarkLine(rtb As RichTextBox, fColor As Color)
Call Mark(rtb, "^---$", Color.White, fColor)
End Sub

Private Sub Mark(ByVal rtb As RichTextBox, ByVal pattern As String, ByVal bColor As Color, fColor As Color)
Dim rOptions As RegexOptions = RegexOptions.IgnoreCase Or RegexOptions.Multiline
Dim regex As New Regex(pattern, rOptions)
For Each m As Match In regex.Matches(rtb.Text)
rtb.SelectionStart = m.Index
rtb.SelectionLength = m.Length
rtb.SelectionColor = fColor
rtb.SelectionBackColor = bcolor
Next
End Sub

Ich habe den Code mal ein wenig angepasst. Die einzelnen Begriffe habe ich in Form von regulären Ausdrücken gruppiert.

Dein Fehler lag in den vielen "rtb.SelectionX"-Eigenschaften, die an den falschen Stellen gesetzt wurden. Dadurch ging die eigentliche Formatierung verloren und war letztendlich durcheinander.

Kommentar von Wissididom ,

Jetzt klappt es sehr gut, jedoch würde ich gerne noch, dass wenn man kein Leerzeichen zwischen reinschreibt es auch nicht markiert wird (z. B. wird Vers1 markiert obwohl zwischen Vers und 1 kein Leerzeichen drin ist. Vielleicht hast eine Lösung dafür, ich wäre dir sehr dankbar.

Kommentar von CrystalixXx ,

Das könnte hiermit klappen:

Private Sub MarkWord(rtb As RichTextBox, word As String, bColor As Color)
Call Mark(rtb, "^" & word & "( +\d*)?$", bColor, Color.Black)
End Sub

Ich habe das zusätzliche Pattern gruppiert. Das Leerzeichen muss nun in Kombination mit der Zahl mindestens einmal vorhanden (dafür das +). Die Kombination aus beiden hingegen darf null oder ein mal vorhanden sein (dafür das ?).

Kommentar von Wissididom ,

Danke, es klappt

Kommentar von Wissididom ,

Jetzt ist noch ein Problem aufgetaucht:

Wenn nach z. B. Vers keine Zahl steht und man nach Vers mehrere Leerzeichen macht werden diese Leerzeichen auch markiert, ich  will jedoch, dass es nur markiert wird, wenn nur ein Leerzeichen ohne Zahl dahinter steht. Ich hoffe man versteht, was ich meine.

Kommentar von CrystalixXx ,

Ein besserer Ausdruck fällt mir nicht ein:

Private Sub MarkWord(rtb As RichTextBox, word As String, bColor As Color)
Call Mark(rtb, "^(" & word & "|" & word & " \d*)$", bColor, Color.Black)
End Sub
Kommentar von Wissididom ,

Danke, es hat funktioniert

Antwort
von CrystalixXx, 37

Ich bin mit regulären Ausdrücken nicht ganz so sehr vertraut, aber so sollte es funktionieren:

Dim wordToHighlight As String = "bridge"
Dim regexPattern As String = "(?<=\s)" & wordToHighlight
Dim regexOptions = System.Text.RegularExpressions.RegexOptions.IgnoreCase

Dim regex As New System.Text.RegularExpressions.Regex(regexPattern, regexOptions)
For Each m As System.Text.RegularExpressions.Match In regex.Matches(RichTextBox1.Text)
RichTextBox1.SelectionStart = m.Index
RichTextBox1.SelectionLength = m.Length
RichTextBox1.SelectionBackColor = Color.Red
Next

Für den Fall, dass das Wort nur dann hervorgehoben werden soll, wenn es alleine in einer Zeile steht, dann könntest du folgendes Pattern versuchen:

Dim regexPattern As String = "(?<=\s)" & wordToHighlight & "((?=\n)|\z)"
Kommentar von Wissididom ,

Den oberen Codevorschlag habe ich ausprobiert, der hat aber gar nichts markiert. Dieser Code markiert wenigstens die einzelnen Worte:

Private Sub Mark(ByVal rtb As RichTextBox, ByVal word As String, ByVal bcolor As Color)
Dim matchc As MatchCollection = Regex.Matches(rtb.Text.ToLower, word.ToLower)
For Each m As Match In matchc
rtb.Select(m.Index, m.Length)
rtb.SelectionBackColor = bcolor
rtb.SelectionColor = Color.White
rtb.Select(m.Index + m.Length, 0)
rtb.SelectionBackColor = Color.White 'rtb.SelectionColor = Color.Black
Next
End Sub

Aber wie gesagt bei diesem Code findet er Pre-Bridge, markiert es, danach markiert er Bridge innerhalb von Pre-Bridge rot.

Kommentar von CrystalixXx ,

Hm, dann versuch mal folgendes:

Private Sub Mark(ByVal rtb As RichTextBox, ByVal word As String, ByVal bcolor As Color)
Dim rPattern As String = "(?<!\S)" & word
Dim rOptions As RegexOptions = RegexOptions.IgnoreCase

Dim regex As New Regex(rPattern, rOptions)
For Each m As Match In regex.Matches(rtb.Text)
rtb.SelectionStart = m.Index
rtb.SelectionLength = m.Length
rtb.SelectionBackColor = bcolor
Next
End Sub

Ich habe das Pattern geändert. Es wird nach dem Wort gesucht, aber nur dann als Match gewertet, wenn das Zeichen unmittelbar vor dem Wort kein Whitespace-Zeichen ist. Damit ist "bridge" auch ein Match, wenn es das erste Wort in der RTB ist. (Das war vorher nicht der Fall.)

Keine passende Antwort gefunden?

Fragen Sie die Community