[RegExp] Splitten, maar niet tussen '' en ()

Pagina: 1
Acties:
  • 117 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik wil graag de volgende tekst "op komma" splitten: test,(te,st),'te,st',('te,st')
En als resultaat heb ik nodig:
(0) = test
(1) = (te,st)
(2) = 'te,st'
(3) = ('te,st')

Nu heb ik 't (donkerbruine) vermoeden, dat ik hier regular expressions moet gebruiken, maar daar schijn je eerst een handvoel boeken over te moeten lezen. Want via Google kom ik niet verder dan "niet-splitten-tussen-quotes". (http://www.4guysfromrolla.com/webtech/120400-1.3.shtml)

Wie kan mij hierbij assisteren? ;(

[ Voor 9% gewijzigd door Verwijderd op 20-01-2005 10:29 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Wow... is dit echt zo moeilijk, zelfs voor experts? O-)

(Ik ben al zelf 'n functie aan 't schijven die per teken een string doorloopt om het gewenste effect te bereiken... maar zo'n regexp is natuurlijk veel mooier...)

Acties:
  • 0 Henk 'm!

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Welke regexp heb je zelf tot nu toe al gebrouwd?

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Acties:
  • 0 Henk 'm!

  • BtM909
  • Registratie: Juni 2000
  • Niet online

BtM909

Watch out Guys...

Via de FAQ van /14 is er ook een mooi topic te vinden ;)

P&W FAQ - Regular expressions

Ace of Base vs Charli XCX - All That She Boom Claps (RMT) | Clean Bandit vs Galantis - I'd Rather Be You (RMT)
You've moved up on my notch-list. You have 1 notch
I have a black belt in Kung Flu.


Acties:
  • 0 Henk 'm!

  • PhoeniX-
  • Registratie: Juni 2000
  • Laatst online: 01-09 10:26
Als het je lukt om het niet tussen quotes te laten splitten, lijkt me het eenvoudig om ditzelfde voor ronde haken te doen?

Blader anders eens op www.regularexpressions.info - dat verduidelijkt alles erg goed (vind ik).

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb nu:
code:
1
(?=([^']*'[^']*')*(?![^']*'))

(als onderdeel van 'n stukje VBScript code)
Ik heb geprobeerd om er een "haakjes"-versie van te maken, zoals:
code:
1
(?=([^\(]*\([^\(]*\()*(?![^\)]*\)))

Maar dat werkt niet/verkeerd... Output, 1 array element:
code:
1
test,(te,st),'te,st',('te,st')

(Da's de originele string) Dus ik zal er wel te simpel over denken ofzo...

[ Voor 12% gewijzigd door Verwijderd op 21-01-2005 13:41 ]


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Ik heb het even geprobeerd en ik ben hier op gekomen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

$subject = "test,(te,st),'te,st',('te,st')";

$regex = '/(?<!\()[^\(\)\,]*?\,(?![^\(\)\,]+\))/u';

//$regex = '/\,(?![^\(\,]+\))/';

$result = preg_split($regex, $subject);

var_dump($result);

?>

Ik heb alles geprobeerd om het ungreedy te houden, maar dat weigert hij blijkbaar. De tweede versie werkt wel, maar niet goed als haakjes niet matchen. Ik weet niet hoe belangrijk dat is, maar dat moet je zelf dus even bepalen. Mischien kom je hier wel verder mee.

(even aangenomen dat je php gaat gebruiken)

[ Voor 19% gewijzigd door Michali op 21-01-2005 13:59 ]

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

Verwijderd

De niet-reguliere werkende oplossing (vrij logisch al je hem bekijkt):

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// string
$str = "test,(te,st),'te,st',('te,st')";

// doorlopen
$openHaakje = 0;
$openAanh   = 0;
$tmp        = null;
$catcher    = array();

for($c=0; $c<strlen($str); $c++)
{
    
    if($str[$c] == "(")
    {
        $openHaakje = 1;
    } else
    if($str[$c] == ")")
    {
        $openHaakje = 0;
    }

    if($str[$c] == "'")
    {
        $openAanh == 1 ? $openAanh = 0 : $openAanh = 1;
    }

    $tmp .= $str[$c];

    if(($str[$c] == "," && $openHaakje == 0 && $openAanh == 0) || ($c == (strlen($str)-1)))
    {       
        $catcher[] = $tmp;
        $tmp = null;
    }

}

echo '<pre>';
print_r($catcher);
echo '</pre>';


PS Ik ben een ontzettend fan van reguliere expressies, maar het is niet altijd nodig die te gebruiken i.m.o. En ik heb een oplossing in PHP aangedragen, echter de (pseudo) flow kun je natuurlijk ook op een andere taal loslaten.

[ Voor 17% gewijzigd door Verwijderd op 21-01-2005 14:02 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Michali schreef op vrijdag 21 januari 2005 @ 13:57:
Ik heb het even geprobeerd en ik ben hier op gekomen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

$subject = "test,(te,st),'te,st',('te,st')";

$regex = '/(?<!\()[^\(\)\,]*?\,(?![^\(\)\,]+\))/u';

//$regex = '/\,(?![^\(\,]+\))/';

$result = preg_split($regex, $subject);

var_dump($result);

?>

Ik heb alles geprobeerd om het ungreedy te houden, maar dat weigert hij blijkbaar. De tweede versie werkt wel, maar niet goed als haakjes niet matchen. Ik weet niet hoe belangrijk dat is, maar dat moet je zelf dus even bepalen. Mischien kom je hier wel verder mee.

(even aangenomen dat je php gaat gebruiken)
De haakjes kloppen altijd, dus da's geen probleem.
Hij klopt nu bijna; krijg ik de volgende output:
code:
1
2
3
4
5
[0] = test
[1] = (te,st)
[2] = 'te
[3] = st'
[4] = ('te,st')

Maar er mag niet tussen ' gesplit worden.
De output moet dus eigenlijk worden:
code:
1
2
3
4
[0] = test
[1] = (te,st)
[2] = 'te,st'
[3] = ('te,st')

Deze code moet in mijn programmaatje vrij vaak uitgevoerd worden, dus ik heb liever 'n (snelle) regexp dan een loopje.

[ Voor 8% gewijzigd door Verwijderd op 21-01-2005 14:33 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Verwijderd schreef op vrijdag 21 januari 2005 @ 14:33:
[...]
Deze code moet in mijn programmaatje vrij vaak uitgevoerd worden, dus ik heb liever 'n (snelle) regexp dan een loopje.
Eerlijk gezegd denk ik dat dat niet veel verschil gaat maken.

Maar ik kan me vergissen.

Acties:
  • 0 Henk 'm!

Verwijderd

PHP:
1
2
3
4
5
6
7
8
    // string
    echo $str = "huis,(bo,om),'app,el',('pe,er'),";
    
    // doorlopen
    preg_match_all("/\(?'?[a-z,]+'?\)?,/", $str, $matches);

    // echo
    print_r($matches);


Zaak is wel dat de input eindigt op een komma.
Verwijderd schreef op vrijdag 21 januari 2005 @ 15:06:
[...]
Eerlijk gezegd denk ik dat dat niet veel verschil gaat maken.
Maar ik kan me vergissen.
offtopic:
Klopt, maar de TS wil graag een regexp gebruiken geloof ik- het loop voorbeeldje dat ik eerder postte werkt namelijk ook als een spreekwoordelijke tiet..

[ Voor 120% gewijzigd door Verwijderd op 21-01-2005 15:19 ]


Acties:
  • 0 Henk 'm!

  • Grum
  • Registratie: Juni 2001
  • Niet online
Perl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use strict;
my $str = "test,(te,st),'te,st',('te,st')";
my $re = qr/
         (
            \('[^']+'\)
         |
            \([^\)]+\)
         |
            '[^']+'
         |
            [^,]+
         )(?=,|$)
         /x;
print "Testing: $str\n";
print "Match: <$&>\n" while $str =~ m{$re}g;

Geeft:
code:
1
2
3
4
5
Testing: <test,(te,st),'te,st',('te,st')>
Match: <test>
Match: <(te,st)>
Match: <'te,st'>
Match: <('te,st')>

Maar wat moet er gebeuren met:
Perl:
1
2
3
4
5
6
$str = "('te''st),'),test";

A) Mag de (' ... ') matchen als er een ' in staat ? 
   Dan krijgen we: ('te''st),') + test
B) Mag de (' nog matchen met een ) als geen ') staat?
   Dan krijgen we: ('te''st) + ') + test


De bovenstaande code matched voor B. Voor A kan je de onderstaande regex gebruiken:
Perl:
1
2
3
4
5
6
7
8
9
10
11
my $re = qr/
         (
            \('.*?'\)
         |
            \((?!')[^\)]+\)
         |
            '[^']+'
         |
            [^,]+
         )(?=,|$)
         /x;


En ja ik weet dat dit een weinig geoptimaliseerde regex is, je kan em kleiner schrijven. Dit komt alleen de leesbaarheid weinig ten goede :)

Edit:
Even vergeten, als je kleine strings gaat splitten dan kan je het wel met een regexp doen. Ga je echter langere strings splitten dan is het 'doorlopen' van de string teken voor teken (soort van tokenizer) weer sneller.

[ Voor 23% gewijzigd door Grum op 21-01-2005 22:26 ]


Acties:
  • 0 Henk 'm!

  • chielsen
  • Registratie: Oktober 2003
  • Laatst online: 20-09 01:17
je kan natuurlijk ook explode(",", $string) doen.
Die maakt een array van alle stukken tussen komma's.
Pagina: 1