Regular expressions: \" en " onderscheiden

Pagina: 1
Acties:

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025
(jarig!)
Voor een logparser (in Python) gebruik ik een regex die bestaat uit stukjes zoals "([^"]*)"; deze geeft dus alles terug wat er tussen de quotes staat. Nu loop ik echter vast op logs waarin bijvoorbeeld iets als "blah\"mkay" staat. Hierbij wordt blah\ dan gematched, terwijl het natuurlijk de bedoeling is dat blah\"mkay gematched wordt. Hier zijn een paar dingen die ik al geprobeerd heb:

code:
1
2
3
' "((?:(?:[^"])|(?:\\"))*)" ' (los matchen met non-matching groups)
' "([^"(?:\\")]*)" ' (non-matching groepje in character class)
' "([^"]*)(?<!\\\)" ' (negative lookbehind assertion)


Nog meer ideeen?

[ Voor 14% gewijzigd door djc op 20-06-2006 09:29 ]

Rustacean


  • Salandur
  • Registratie: Mei 2003
  • Laatst online: 14:07

Salandur

Software Engineer

' "([^"]*)(?<!\\\)" ' volgens mij heb je een \ te weinig of teveel.

Assumptions are the mother of all fuck ups | iRacing Profiel


  • Daos
  • Registratie: Oktober 2004
  • Niet online
Kan je die \" niet gewoon in je regex proppen? Zoiets als: "((\\"|[^"])*)"

[ Voor 49% gewijzigd door Daos op 20-06-2006 10:26 ]


  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025
(jarig!)
Salandur schreef op dinsdag 20 juni 2006 @ 09:41:
' "([^"]*)(?<!\\\)" ' volgens mij heb je een \ te weinig of teveel.
Ja, nee, stiekem klopt dat wel. De Python interpreter escapet de \\ naar een \, en dan heb ik ook nog een \ nodig om de ) te escapen?

Rustacean


  • Spider.007
  • Registratie: December 2000
  • Niet online

Spider.007

* Tetragrammaton

Ik heb er even met een collega naar gekeken en we komen vooralsnog uit op
code:
1
' "([^"]*(?<!\\\\)(\\\\(\\\\\\\\)*"[^"]*)*)" '
Echter; deze werkt nog niet volledig voor ingewikkeldere input zoals
code:
1
"asdf\"\"asdf"

---
Prozium - The great nepenthe. Opiate of our masses. Glue of our great society. Salve and salvation, it has delivered us from pathos, from sorrow, the deepest chasms of melancholy and hate


  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025
(jarig!)
Spider.007 schreef op dinsdag 20 juni 2006 @ 12:24:
Ik heb er even met een collega naar gekeken en we komen vooralsnog uit op
code:
1
' "([^"]*(?<!\\\\)(\\\\(\\\\\\\\)*"[^"]*)*)" '
Echter; deze werkt nog niet volledig voor ingewikkeldere input zoals
code:
1
"asdf\"\"asdf"
Dus hij is zowel enorm naar als beperkt functioneel? :D

Niet om jullie te bashen ofzo, thanks dat jullie er naar kijken, maar ik zou toch denken dat er voor dit probleem een elegantere oplossing moet zijn. :|

Rustacean


  • Shir
  • Registratie: November 2000
  • Laatst online: 25-11-2025
Deze staat in de library van RegexBuddy:

code:
1
"[^"\\\r\n]*(?:\\.[^"\\\r\n]*)*"

  • Spider.007
  • Registratie: December 2000
  • Niet online

Spider.007

* Tetragrammaton

Gewoon een for-loopje; en dan een vlag bijhouden (oftewel; niet met een regexp op proberen te lossen)? De betere versie is trouwens:
code:
1
' "[^"]*((?<!\\\\)(\\\\\\\\)*\\\\"[^"]*)*(?<!\\\\)(\\\\\\\\)*" '

---
Prozium - The great nepenthe. Opiate of our masses. Glue of our great society. Salve and salvation, it has delivered us from pathos, from sorrow, the deepest chasms of melancholy and hate


  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025
(jarig!)
Spider.007 schreef op dinsdag 20 juni 2006 @ 13:39:
Gewoon een for-loopje; en dan een vlag bijhouden (oftewel; niet met een regexp op proberen te lossen)?
Het is voor een parser voor Apache logbestanden, die vrij snel vrij groot kunnen worden.

Ik had eerst ook nog een soort van split()-based oplossing, maar dat was niet erg robuust. De robuustheid/performance trade-off van deze leek me wel goed, maar dit viel toch weer wat tegen.

Rustacean


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:28

crisp

Devver

Pixelated

Ik kom hierop:
code:
1
' "(((?<!\\\\)(\\\\\\\\)*\\\\"|[^"])*)" '

maar dit soort dingen kan je inderdaad beter met een tokenizer oplossen

Intentionally left blank


  • Salandur
  • Registratie: Mei 2003
  • Laatst online: 14:07

Salandur

Software Engineer

een string matchen is toch:
Perl:
1
/".*?(?<\)"/

in een andere taal wordt het dan
Java:
1
"\".*?(?<\\)\""

[ Voor 29% gewijzigd door Salandur op 20-06-2006 14:31 ]

Assumptions are the mother of all fuck ups | iRacing Profiel


  • Daos
  • Registratie: Oktober 2004
  • Niet online
Daos schreef op dinsdag 20 juni 2006 @ 10:25:
Kan je die \" niet gewoon in je regex proppen? Zoiets als: "((\\"|[^"])*)"
Ik heb mijn idee eventjes getest:
code:
1
2
3
4
>>> import re
>>> p = re.compile(r'"((\\"|[^"])*)"')
>>> print p.findall(r'"test1" "test2"x"test3" "test\"4\""')
[('test1', '1'), ('test2', '2'), ('test3', '3'), ('test\\"4\\"', '\\"')]


Waarom verdwijnen de "-jes en waarom komen die '1' en '2' etc er ook bij?


[edit]
Dit werkt wel:
code:
1
2
3
>>> p = re.compile(r'".*?[^\\]"')
>>> print p.findall(r'"test1" "test2"x"test3" "test\"4\""')
['"test1"', '"test2"', '"test3"', '"test\\"4\\""']


[edit2]
En dat ding van Salandur ook:
code:
1
2
3
>>> p = re.compile(r'".*?(?<!\\)"')
>>> print p.findall(r'"test1" "test2"x"test3" "test\"4
['"test1"', '"test2"', '"test3"', '"test\\"4\\""']

[ Voor 82% gewijzigd door Daos op 20-06-2006 14:52 ]


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:28

crisp

Devver

Pixelated

Daos, waar je dan geen rekening mee houdt is dat het escape-teken zelf ook weer escaped kan zijn... (plus dat je geen rekening houdt met meerdere escaped quotes binnen dezelfde string)

[ Voor 31% gewijzigd door crisp op 20-06-2006 16:24 ]

Intentionally left blank


Verwijderd

Ik gebruik soortgelijk iets voor een syntax highlighter. De basis daarvan komt neer op:

Maak er maar wat van wat jij nodig hebt (in mijn geval zet ik er opmaak omheen, dus ik heb de complete string niet nodig, dus daar valt wel iets beters van te maken.

edit:
Onderstaande is inmiddels geteste javasdcript code, valt vast om te schrijven naar Python

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function logparse(input)
{
    var tokens = input.split("\"");
    var strings = new Array(); 
    for (var i = 0, inside = false; i < tokens.length; i++) 
    {
        if (inside == false) 
        { 
            inside = i; 
        } 
        else if (tokens[i-1].match(/[^\\]{1}(\\\\)*$/) || tokens[i-1] == '') 
        {
            // Dus jouw string is alles tussen index inside en i; doe er mee wat je wil; 
            strings.push(tokens.slice(inside, i).join("\"")); 
            inside = false; 
        }
    }
    
    return strings;
}


Dus inderdaad wat al gezecht is, een tokenizer.

[ Voor 104% gewijzigd door Verwijderd op 20-06-2006 17:33 ]


  • DeMoN
  • Registratie: Maart 2001
  • Laatst online: 17-02 18:05

DeMoN

Pastafari

Ff (deels)offtopic, maar kennen jullie kodos?
Die is echt zeer geschikt voor dit soort dingen :)

http://kodos.sourceforge.net

[ Voor 3% gewijzigd door DeMoN op 20-06-2006 16:54 ]

Gamertag: Cosmicv0id
"Het woord Gods is voor mij niets meer dan een expressie en het product van menselijke zwakheid. De Bijbel is een verzamelwerk van legendes die achtenswaardig zijn maar ook primitief en kinderachtig.'' - Albert Einstein


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:28

crisp

Devver

Pixelated

Tokenize voorbeeldje:
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
$text = 'hoihoi "tyralala\"hoi\"" "tral\\\\\\\\\\\\\\\\\\\\\"ala"';
$pos = -1;
$strings = array();
$i = 0;

while (($pos = strpos($text, '"', ++$pos)) !== false)
{
    $strings[$i] = '';
    $skipnext = false;

    while (($c = $text[++$pos]) !== '')
    {
        if (!$skipnext)
        {
            if ($c == '\\')
                $skipnext = true;
            elseif ($c == '"')
                break;
        }
        else
            $skipnext = false;

        $strings[$i] .= $c;
    }

    $i++;
}

print_r($strings);

Intentionally left blank


Verwijderd

Crisp, zie bovenstaande. Had hem al voorgedaan in javascript ;)

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:28

crisp

Devver

Pixelated

Verwijderd schreef op dinsdag 20 juni 2006 @ 17:13:
Crisp, zie bovenstaande. Had hem al voorgedaan in javascript ;)
Ja, maar jij hebt toch weer een ranzige regexp nodig :P

Intentionally left blank


Verwijderd

En zo te zien heb ik die nog ergens tijdens het copieren nog vernagelt ook :P
*Gaat zich diep schamen.

edit:
inmiddels fixxed, scheen dat lege strings in JS niet matchen met /^$/, tenminste niet bij mij


Oja: heb het met regexxen gedaan omdat hij namelijk niet static qua code is, maar per type is ie dynamisch in te stellen met een bult settings ;). Dus die regex was onvermijdelijk :(.

[ Voor 66% gewijzigd door Verwijderd op 20-06-2006 17:40 ]

Pagina: 1