Avatar billede Syska Mester
30. august 2010 - 01:56 Der er 10 kommentarer og
1 løsning

Match og extract

Yo,

Jeg bruger .NET til dette, så håber min kode stadig kan forstås og der kommer nogen gode forslag som kan gøre mig lidt klogere.

Jeg har følgende lige nu:
MacroRegex = new Regex(@"\$(?<Name>[A-z_]+?)(\((?<Param>[\S ]*?)(\|(?<Param>[\S ]+?))*\))?\$", RegexOptions.Compiled);

Dette kan match:
$DATE$ # Date i Name group og ingenting i Param.
$DATE(5)$ # Date i Name group, og 5 i Param.
$UPPER(some string)$
$DATE($DATE$)$ - virker fint, da match af enden er unik, men nedestående virker ikke.

Alt virkede næsten ... problemet kommer ved:
$DATE($TIME(5)$)$ - Param indeholder nu "$DATE(5" ... og ja, den skulle gerne indeholde "$DATE(5)$ ... og ja, det er forstående lidt ... men hvordan dælen løser jeg det.

Jeg er helt blank for ideer, og er ikke specielt meget inde i Regex, så der er sikkert en smart måde det kan løses på.

Jeg kan godt ændre i min måde at match stringe på, hvis det så kan løses på en bedre/nemmere måde, bare buttom result bliver det samme.

mvh
Avatar billede Syska Mester
30. august 2010 - 02:06 #1
Lader til mine google skills er bedre end mine regex skills.

http://weblogs.asp.net/jeff/archive/2004/10/25/247675.aspx

og linket til:
http://oreilly.com/catalog/regex2/chapter/ch09.pdf

Men jeg lytter gerne til flere ideer ... og er endnu ikke sikker på at dette løser mit problem, men krydser fingre for det.
Avatar billede Syska Mester
30. august 2010 - 02:08 #2
Virker til at mine googlle skills er bedre end mine Regex.

Der er en på i denne blog post:
http://weblogs.asp.net/jeff/archive/2004/10/25/247675.aspx

som linker til:
http://oreilly.com/catalog/regex2/chapter/ch09.pdf
#Matching Nested Constructs

mvh
Avatar billede Syska Mester
30. august 2010 - 02:08 #3
Virker til at mine googlle skills er bedre end mine Regex.

Der er en på i denne blog post:
http://weblogs.asp.net/jeff/archive/2004/10/25/247675.aspx

som linker til:
http://oreilly.com/catalog/regex2/chapter/ch09.pdf
#Matching Nested Constructs

mvh
Avatar billede arne_v Ekspert
30. august 2010 - 03:32 #4
En lidt anden tilgang:

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

namespace E
{
    public class Program
    {
        private static readonly Regex re = new Regex(@"^\$(\w+)(\((.*)\))?\$$", RegexOptions.Compiled);
        private static void Parse(string s, List<string> res)
        {
            if(re.IsMatch(s))
            {
                Match m = re.Match(s);
                res.Add(m.Groups[1].Value);
                if(m.Groups[3].Value != "") Parse(m.Groups[3].Value, res);
            }
            else
            {
                res.Add(s);
            }
        }
        public static List<string> Parse(string s)
        {
            List<string> res = new List<string>();
            Parse(s, res);
            return res;
        }
        public static void Main(string[] args)
        {
            string[] sa = new string[] { "$DATE$",
                                        "$DATE(5)$",
                                        "$UPPER('some string')$",
                                        "$DATE($DATE$)$",
                                        "$DATE($TIME(5)$)$" };
            foreach(string s in sa)
            {
                Console.Write(s + " ->");
                foreach(string e in Parse(s)) Console.Write(" " + e);
                Console.WriteLine();
            }
            Console.ReadKey();
        }
    }
}
Avatar billede Syska Mester
30. august 2010 - 22:53 #5
Yo,

Kan se ideen ... men tror der kan opstå problemer da det skal bruges som en del af en string med flere instances af overstående i.

Hej $USERNAME$, du kommer fra $IP$ ....

og ja, der er sikkert flere scenarier jeg ikke lige har overvejet endnu, men du kan sikkert se ideen.

mvh
Avatar billede arne_v Ekspert
31. august 2010 - 03:49 #6
Ja. Hele ideen i min kode er jo netop at den starter og slutter med $.

Hvis det du har fundet kan bruges, så er det jo fint.

Ellers kunne du lave en ikke-regex-parser. Det er vel primært et spørgsmål om at tælle parenteser og dollar tegn.
Avatar billede Syska Mester
31. august 2010 - 10:45 #7
Ja, jeg har i hvert fald fundet ud af at Regex, måske ikke lige er vejen frem ... det kan i hvert fald være meget besværligt.

Det skal bruges til et oversættelses system jeg roder med for sjov, men den her ting ARGHHHH.

Men måske man skulle prøve at se hvor nem/besværlig en parser ville være at få til at virke godt ... tænke tænke, hvis du har input skal du være meget velkommen :-)

Problemet er også lidt at jeg har nogen macros som resolver til andre ...

$NAME$ kunne blive til $FIRSTNAME$ $LASTNAME$ ... og ja, you get the idea.

Vil prøve at se på det i aften.

mvh
Avatar billede Syska Mester
31. august 2010 - 18:42 #8
Argh, det er jo mega nitten at få lavet på en smart måde, så hvis du har input, lytter jeg gerne.

Skal nok også have lavet mine start/slut tags om, så man bedre kan kende forskel ... tænke tænke ...

mvh
Avatar billede arne_v Ekspert
31. august 2010 - 20:33 #9
Det er jo en fuld macro processor du efterspoerger.

Saadan noget kode ender nemt med at blive noget vaerre snask, hvis man ikke griber det systematisk an.

Her er en halvsnasket loesning:

using System;
using System.Collections.Generic;

namespace E
{
    public class Macro
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }
    public class MacroProcessor
    {
        private List<Macro> macros = new List<Macro>();
        public void Add(string nam, string val)
        {
            macros.Add(new Macro { Name = nam, Value = val });
        }
        public string Process(string s)
        {
            string res = "";
            string mac = null;
            string arg = null;
            bool inmacro = false;
            for(int i = 0; i < s.Length; i++)
            {
                switch(s[i])
                {
                    case '$':
                        if(inmacro)
                        {
                            //Console.WriteLine("mac = " + mac);
                            for(int j = macros.Count - 1; j >= 0; j--)
                            {
                                if(mac == macros[j].Name)
                                {
                                    mac = macros[j].Value.Replace("@1", arg);
                                }
                            }
                            //Console.WriteLine("mac = " + mac);
                            res += Process(mac);
                            inmacro = false;
                        }
                        else
                        {
                            inmacro = true;
                            mac = "";
                        }
                        break;
                    case '(':
                        int par = 1;
                        arg = "";
                        i++;
                        while(par > 0)
                        {
                            if(s[i] == '(')
                            {
                                par++;
                            }
                            else if(s[i] == ')')
                            {
                                par--;
                            }
                            if(par > 0)
                            {
                                arg += s[i];
                                i++;
                            }
                        }
                        //Console.WriteLine("arg = " + arg);
                        break;
                    default:
                        if(inmacro)
                        {
                            mac += s[i];
                        }
                        else
                        {
                            res += s[i];
                        }
                        break;
                }
            }
            return res;   
        }
    }
    public class Program
    {
        public static void Test(MacroProcessor mp, string s)
        {
            Console.WriteLine("in  : " + s);
            Console.WriteLine("out : " + mp.Process(s));
        }
        public static void Main(string[] args)
        {
            MacroProcessor mp = new MacroProcessor();
            mp.Add("TEST1", "Dette er test 1");
            mp.Add("TEST2", "Dette er test 2");
            Test(mp, "$TEST1$ & $TEST2$");
            mp.Add("TEST3", "Dette er test @1");
            Test(mp, "$TEST3(3)$");
            Test(mp, "$TEST3('3')$");
            mp.Add("TEST4", "$TEST1$ & $TEST2$");
            Test(mp, "$TEST4$");
            mp.Add("TEST5", "@1");
            Test(mp, "$TEST5($TEST3(3)$)$");
            Console.ReadKey();
        }
    }
}
Avatar billede Syska Mester
31. august 2010 - 21:17 #10
Jeg kan jo ikke sige andet end du løber rundt med en ûber hjerne over dem alle ... det er jo faktisk en meget genial løsning.

Må lige prøve at integrere den i min anden løsning, men det burde ikke være et problem.

Nu har jeg i hvert fald noget lidt bedre at arbejde videre på.

Smid svar, det har du klart fortjent.
Avatar billede arne_v Ekspert
31. august 2010 - 21:45 #11
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester