webForumDet fria alternativet

Regex problem

.NET

18 svar · 1 087 visningar · startad av saw

Medlem sedan mars 20011 880 inlägg
Frågan#1

Jag skulle vilja ha hjälp med ett mönster(patton).
Den skall hitta allt inom () t ex ( Am7). Hur bör ett sådant mönster se ut?

Medlem sedan nov. 20051 317 inlägg
#2

(*.?)

Kanske?

Medlem sedan sep. 20005 700 inlägg
#3

\(*\)

Medlem sedan mars 20011 880 inlägg
#4

Nja det lyckades inte riktigt.
När jag försöker med

(*.?)
ERROR
parsar (*.?) - Kvantifieraren {x,y} följer på ingenting.

När jag försökte med

\\(*\\)

så visade den enbart ).
Kanske jag inte har skrivit min kod ordentligt?

string kollaM = "\\(*\\)";
            Regex repost = new Regex(kollaM,RegexOptions.IgnoreCase|RegexOptions.Compiled);
            Match m;
            m = repost.Match(richTextBoxEx1.Text);
            if (m.Success)
            {
                richTextBoxEx1.SelectionStart = m.Index;
                richTextBoxEx1.SelectionLength = m.Length;
                label6.Text = m.Value.ToString();
            }

Ser min kod mysko ut?

Medlem sedan juni 20019 519 inlägg
#5
\(*\)

Denna kommer bara träffa:
()
(()
((() osv.

\(.*\)

. = vilket tecken som helst, * mellan 0 till hur många gånger som hellst (så många gånger som möjligt).

Medlem sedan mars 20011 880 inlägg
#6

Nu börjadet att hända någonting men jag får med mig parentesen (G7m).
Jag skulle alltså vilja ha G7m.

Medlem sedan juni 20019 519 inlägg
#7

RegExp:

\((.*)\)

För att lägga in träffen i en grupp och använd

m.Groups[1].ToString()

för att få ut G7m (tror jag)

Medlem sedan mars 20011 880 inlägg
#8

Nu är vi på rätt väg, men ett problem (vad jag är ute efter är att få ackorden att ljuda).
Om det bara finns ett ackord (Gm7) då är det inga problem, men om det finns flera då
läser scriptet in det som ( (G) (C) (F) (C) )
Jag borde väll kunna ha en foreach slinga eller något?

Medlem sedan juni 20019 519 inlägg
#9
try {
	Regex regexObj = new Regex(@"\((.*)\)", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
	Match matchResults = regexObj.Match(richTextBoxEx1.Text);
	while (matchResults.Success) {
		label6.Text += matchResults.Groups[1].Value;
		matchResults = matchResults.NextMatch();
	} 
} catch (ArgumentException ex) {
	// Syntax error in the regular expression
}

Om Du har en text som ser ut:

"(G) (C) (F) (C)"

Om du har en "grupp":

( (G) (C) (F) (C) )

Så kommer den retunera " (G) (C) (F) (C) "

Frågan är lite mer: Vilka tecken är godkända att ha mellan () ?(blåbär) skall den träffa den, skall den träffa mellanslag osv?

Medlem sedan sep. 20005 700 inlägg
#10

voigtann1 skrev:

\(*\)

Denna kommer bara träffa:
()
(()
((() osv.

\(.*\)

. = vilket tecken som helst, * mellan 0 till hur många gånger som hellst (så många gånger som möjligt).

Tack, jag var visst lite snabb!

Medlem sedan mars 20011 880 inlägg
#11

Tack för att du försöker att hjälpa mig.
Först

Match matchResults = regexObj.Match(richTextBoxEx1.SelectedText);
[/kod
..det måste vara så eftersom det är markerad text det är tal om.
Sen hur den skall leta, tänkt dig så här:

Blinka lilla stjärna där
(C)         (F)       (C)
hur jag undrar var du är..
(F)      (C)      (G7)   (C)

Med andra ord så kan hela eller dela av dokumentet markeras.
Därefter så kommer..
[kod]

resultat = m.Groups[1].ToString();
                string sUtakat = "inget";
                string sAckord = "";
                if (resultat.Contains("#"))
                {
                    sAckord = resultat.Substring(0, 2);
                    sUtakat = resultat.Substring(2);
                }
               else
                {
                    sAckord = resultat.Substring(0, 1);
                    sUtakat = resultat.Substring(1);
                }
                if (sUtakat.Length == 0)
                    sUtakat = "inget";
                PlayAckord(sAckord, sUtakat);

Detta innebär ju att jag måste ha ackorden "en efter en".
Jag har haft detta fungerande tidigare, men jag fich en crach och jag minns
tyvärr inte hur jag gjorde. :l

Medlem sedan juni 20019 519 inlägg
#12

Så när du har markerat

Blinka lilla stjärna där
(C) (F) (C)
hur jag undrar var du är..
(F) (C) (G7) (C)

Så skall resultatet bli:
CFCFCG7C?

Medlem sedan mars 20011 880 inlägg
#13

Alldeles korrekt.
Eller så här
C
F
C ...
dvs att detta borde nog ligga i en loop där ett ackord i sänder kommer fram.

Medlem sedan juni 20008 205 inlägg
#14

Vad sägs om att läsa dokumentationen lite? :) För att få fram alla sekvenser som matchar en regexp använder man Regex.Matches(string):

            string subject =
                "Blinka lilla stjärna där" +
                "(C)         (F)       (C)" +
                "hur jag undrar var du är.." +
                "(F)      (C)      (G7)   (C)";
            Regex re = new Regex(@"\((.*?)\)");
            foreach (Match match in re.Matches(subject))
            {
                Console.WriteLine(match.Groups[1]);
            }

ger

C
F
C
F
C
G7
C

red. *? är bättre för oss eftersom * är greedy, dvs den försöker matcha så mycket som möjligt. Eftersom "." matchar allt förutom radbrytningar, matchar den även högerparantes, vilket innebär att "\(.*\)" effektivt betyder "allt fr.o.m. första vänsterparantesen t.o.m. sista högerparantesen på varje rad". Använder man *? istället försöker regexpen matcha så lite som möjligt, vilket innebär att "\(.*?\)" betyder "allt från och med varje vänsterparantes t.o.m. nästa högerparantes". Lägger man sedan till så att det blir "\((.*?)\)" får vi en capturing group på innehållet mellan paranteserna, så att vi direkt kan hämta ut det med match.Groups[1].

Medlem sedan juni 20019 519 inlägg
#15

Det bästa mönstret är:

\(([^\)]+)\)

Då du vet att den skall ha en ) som avslut.

Medlem sedan juni 20008 205 inlägg
#16

Ännu bättre med något som bara plockar fram giltiga ackord, typ

\(([a-hA-H])(#?)(\d?)\)

dvs, först en ton, eventuellt följt av ett kors, eventuellt följt oktavnummer, alla i varsin capture group. Går förstås att göra ännu bättre valideringar, exempelvis finns väl inte B# eftersom det blir C.

Medlem sedan mars 20011 880 inlägg
#17

Tack nu har jag någonting att fortsätta med.

[REDIGERAT]
Nej tyvärr det fungerar inte som jag hadde tänkt. Jag försöker att läsa och
leta men jag hittar ingenting som hjälper mig, därför så fortsätter jag med
denna tråden.
Så här ser nu koden ut:

string resultat = "";
                string sUtakat = "inget";
                string sAckord = "";

                string subject = richTextBoxEx1.SelectedText;
                Regex re = new Regex(@"\(([^\)]+)\)");
                foreach (Match match in re.Matches(subject))
                {
                    resultat = match.Groups[1].ToString();
                    if (resultat.Contains("#"))
                    {
                        sAckord = resultat.Substring(0, 2);
                        sUtakat = resultat.Substring(2);
                    }
                    else
                    {
                        sAckord = resultat.Substring(0, 1);
                        sUtakat = resultat.Substring(1);
                    }
                    if (sUtakat.Length == 0)
                        sUtakat = "inget";
                    PlayAckord(sAckord, sUtakat);

                    label6.Text = match.Groups[1].ToString();
                }

Problemet är att scriptet läser alla ackorden med en gång, jag är mera inne
på en loop så att ackorden säses av ett efter ett, och spelas ett efter ett.

Medlem sedan juni 20008 205 inlägg
#18

Vadå "läser alla med en gång"? Den läser ett ackord åt gången, om än jävligt snabbt. Vill du att ett ackord ska spela klart innan nästa påbörjas får du väl lägga in en sleep i loopen eller i PlayAckord eller nåt.

Medlem sedan mars 20011 880 inlägg
#19

Tack spango det var just vad jag gjorde, men jag tänkte att det var för "hemasnickrat".

279 ms totalt · 4 externa anrop · v20260731065814-full.6fe65c25
136 ms — deklarationer (db)
0 ms — hämta statistik (cache)
140 ms — hämta tråd, inlägg och bilagor (db)
131 ms — ändringar (db)