PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [.NET] Suche nach Regex-Pattern


Gast
2009-07-08, 18:51:08
Hallo!

Ich bin jetzt schon den halben Tag dabei, ein Regex-Pattern (für .NET) zu finden, welches folgendendermaßen agiert.

Obere Zeile die Eingabe, darunter die Matches welche rauskommen sollen (durch Komma getrennt):

1.
!befehl param1 param2
!befehl, param1, param2 (3 Treffer)

2.
!befehl param1 pa ram2
befehl, param1, pa, ram2 (4 Treffer)

3.
!befehl param1 "pa ram2"
!befehl, param1, pa ram2 (3 Treffer)

4.
!befehl param1, "pa ram2
!befehl, param1, "pa, ram2 (4 Treffer)


Randnotiz: die Parameterliste soll dynamisch lang sein, also keine Beschränkung auf nur 2 Params wie in meinen Beispielen. Es dürfen auch 0 Parameter vorkomen, sprich nur der Befehl dastehen.

Ich denke, es ist ersichtlich, was erreicht werden soll. Der erste Treffer soll der Befehl sein (das erste Wort also), der zweite Treffer das darauffolgende Wort usw.
Leerstelle bedeutet, es fängt ein neues Wort an, es sei denn, es werden Anführungszeichen benutzt. Wurde nur ein Anfürhungszeichen angegeben und das öffnende bzw. schließende vergessen, so bewirkt das nichts und das Anführungszeichen gehört zum Text.

Was daran kompliziert sein soll? Ich verzweifle gerade!

Okay, der Befehl sollte kein Problem sein, den Anfang könnte man evt. so machen:
(![\w]+)

Aber bei den Parametern gehts dann los. Einfachheitshalber wollte ich das ganze erstmal ohne die optionalen Anführungszeichen hinbekommen. (Das (?: ... bedeutet in .NET, dass die Gruppe nur zur Regexlogik gehört und nicht extrahiert wird.)

^(![\w]+)(?:\s(\w+))*$

Problem: es gbt immer exakt 2 Treffer, egal, ob ich 0 oder 100 Parameter angebe. Bei 0 Params hätte ich gerne auch nur ein Ergebnis (nämlich der Befehl), bei 100 params entsprechend 101. Klar, ich hab ja auch 2 Klammern gesetzt (die eine zählt ja nicht wegen ?: ), aber für was setze ich dann den Sternoperator für die Parameter?

Unabhängig davon bekomme ich es nicht hin, die optionalen Anführungszeichen einzubauen. Der oder-Operator war auf den ersten Blick hilfreich, aber seht selbst:

(\w+)|"([\w\s]+)"

Dieser fischt mir zwar, unabhängig davon ob Anführungszeichen benutzt wurden oder nicht, immer schön den Parameter raus (falls nötig von eben diesen Anführunsgzeichen befreit), aber es existiert daneben auch immer ein leeres ("") Ergebnis, schließlich habe ich ja 2 Klammern gesetzt. Ersetze ich die 2 Klammern durch eine große Klammer um alles drumrum, so habe ich zwar wie gewünscht nur ein Ergebnis, aber dafür werden die Anführungszeichen nicht entfernt.

MANNN!!!!!

Bitte helft mir :(

Trap
2009-07-08, 18:55:50
Das was du da beschreibst ist keine reguläre Sprache => es kann keine Regex für geben.

Mit einem Parser für kontextfreie Grammatiken kann man das so einlesen wie du möchtest.

Gast
2009-07-08, 19:11:14
Hallo,

und was ist daran der nicht-reguläre Teil?
Das mit der dynamischen Anzahl an Parametern scheint hier aber auch zu gehen, oder sehe ich das falsch?:

http://www.eggheadcafe.com/forumarchives/NETcsharp/Jun2005/post23274396.asp

Trap
2009-07-08, 19:19:22
Die Unterscheidung zwischen den Fällen "x" y und "x y ist nicht regulär.

Gast
2009-07-08, 19:33:26
Okay, gut. eigentlich wollte ich jetzt schreiben, dass ihr das mit den Anführungszeichen vergessen könnt und stattdessen nur was zur dyn. Parameteranzahl schreibt.
Aber eigentlich kann ich dann gleich direkt in C# trim() anwenden, alle mehrfachen Leerzeichen zu einem ersetzen und dann an Leerzeichen zum String-Array trennen, das ist wohl besser, oder?

Achja, noch ne Frage zu Traps "Parser für kontextfreie Grammatiken".
Gibts da was fertiges oder muss man den selbst schreiben? Habe da schon ne Idee vonwegen String in Char-Array und dann von vorne nach hinten durchlaufen etc.

Monger
2009-07-08, 19:40:23
Die Unterscheidung zwischen den Fällen "x" y und "x y ist nicht regulär.
Sorry, könntest du mir das näher erklären? Bin nicht ganz sicher was du meinst. Ich seh so spontan keinen Grund, wieso man dieses Konstrukt nicht per regulären Ausdruck abbilden können soll. Wird halt hässlich.

Pinoccio
2009-07-08, 19:51:18
Okay, gut. eigentlich wollte ich jetzt schreiben, dass ihr das mit den Anführungszeichen vergessen könnt und stattdessen nur was zur dyn. Parameteranzahl schreibt.
Aber eigentlich kann ich dann gleich direkt in C# trim() anwenden, alle mehrfachen Leerzeichen zu einem ersetzen und dann an Leerzeichen zum String-Array trennen, das ist wohl besser, oder?In JAVA würde ich es so machen:
1.) mehrfache Leerzeichen wegmachen mit replace("\s{2,}"," ") (Beliebig viele Whitspace-Zeichen durch ein Leerzeichen ersetzen)
2.) an Leerzeichen Trennen mit split(" ")
3.) durchiterieren und beginnende Anführungszeichen entfernen

Wenn es in deiner Sprache auch geht ...
Ein einzelnes Regexpattern ist sicherlich mächtiger (wenn es geht) aber imho viel schwerer zu warten.

mfg

Gnafoo
2009-07-08, 21:48:36
Wie wäre es damit:


using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Test2
{
class Program
{
static void Main(string[] args)
{
string[] str = new string[]
{
"!befehl param1 param2",
"!befehl param1 pa ram2",
"!befehl param1 \"pa ram2\"",
"!befehl param1 \"pa ram2",
"!befehl param1 \"pa ram2 \"pa ram 3\""
};

Regex r = new Regex(@"
^(?:!(?<cmd>\w+)) (?# Befehl)
(?:\s+(?:
(?:""(?<par>[^""]+)"") | (?# Quotes)
(?<par>[\w""]+) (?# Param)
))*
$", RegexOptions.IgnorePatternWhitespace);

foreach (string s in str)
{
Console.WriteLine("String: " + s);

Match m = r.Match(s);
if (m.Success)
{
Console.WriteLine("Cmd: " + m.Groups["cmd"].ToString());

Group parGroup = m.Groups["par"];
foreach (Capture c in parGroup.Captures)
{
Console.WriteLine("Par: " + c.ToString());
}
}
else
{
Console.WriteLine("Fehler");
}

Console.WriteLine();
}

Console.ReadLine();
}
}
}


Funktioniert zumindest für deine Beispiele so wie du es willst.

Trap
2009-07-09, 11:58:45
Sorry, könntest du mir das näher erklären? Bin nicht ganz sicher was du meinst. Ich seh so spontan keinen Grund, wieso man dieses Konstrukt nicht per regulären Ausdruck abbilden können soll.
Stimmt, es geht ja nicht um gleiche Anzahl von " sondern um 1 oder 0 mal, das könnte doch regulär sein. Sry für die Verwirrung.

Gnafoo
2009-07-09, 13:00:52
Interessanterweise kann man mit den "regulären" Ausdrücken bei .NET trotzdem Klammerstrukturen erfassen. Siehe:
http://blogs.msdn.com/bclteam/archive/2005/03/15/396452.aspx

Allerdings ist das nicht besonders hübsch :D.

MadMax@
2009-07-09, 23:00:50
Pumping Lema 4thw.

Sorry das war Spam aber seit Jahren warte ich darauf das das Ding mal nützlich sein kann.

PS:
Bitte nicht fragen wie man das in diesem Fall anwendet ich habe keine Ahnung mehr.