[php] Van 1 variabel meerdere maken (met escape karakter)

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Anoniem: 166653

Topicstarter
Ik heb dus hetvolgende probleem: (Misschien beter uitgelegd in mijn vorige topic: [rml][ PHP] Meerdere variabelen maken van 1 variabel[/rml])
PHP:
1
$string="iets=blaat|iets2=blabla||blabla|iets3=nogmeer tekst|||test4=laatste test";

Nu wil ik dus de volgende array krijgen: (let op: || is dus een escape karakter voor | aangezien je die niet kunt gebruiken omdat anders de code word gesplit!)
code:
1
2
3
4
5
6
Array (
    [0] => "iets=blaat",
    [1] => "iets2=blabla|blabla",
    [2] => "iets3=nogmeer tekst|",
    [3] => "test4=laatste test"
)

Nu had ik al de volgende code in een vorig topic gekregen, namelijk:
PHP:
1
$keyValuePairs = preg_split("/(?<!\\|)\\|(?!\\|)/", $string);

Het probleem dat ik hiermee krijg is dat hij de volgende array gaat maken:
code:
1
2
3
4
5
Array (
    [0] => "iets=blaat",
    [1] => "iets2=blabla||blabla",
    [2] => "iets3=nogmeer tekst|||test4=laatste test"
)

Terwijl hij na 2 || weer opnieuw moet beoordelen of hij moet worden gesplit of niet. Nu heb ik zelf een script gemaakt die letter voor letter gaat kijken wat hij moet doen:
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
function parser($string)
{
    $temp = Array();
    $array = 0;
    $found_escape = 0;
    for($x=0;$x<strlen($string);$x++)
    {
        if($found_escape && $string[$x] != "|")
        {
            $array++;
            $temp[$array] .= $string[$x];
            $found_escape = 0;
        }
        elseif(!$found_escape && $string[$x] == "|")
        {
            $found_escape = 1;
        }
        elseif($found_escape && $string[$x] == "|")
        {
            $found_escape = 0;
            $temp[$array] .= $string[$x];
        }
        else
        {
            $temp[$array] .= $string[$x];
        }
    }
    return $temp;
}

Werkt opzich perfect maar heeft 1 groot nadeel en dat is de parsetijd. Hij doet er namelijk 60 keer langer over dan het hier boven opgegeven preg_split script. Over dit script gaat straks tot 8 meg aan data, daarom zoek ik een zo snel mogelijke functie, heeft iemand nog ideeën om deze functie te versnellen? of bovenstaand script (preg_split) goed te laten werken?

Let wel, de normale functies zoals: Split en Explode gaan hier dus niet zomaar op. (simpel splitten op | eveneens niet, omdat er een escape aanwezig is (de mogelijkheid moet dus blijven bestaan de | te gebruiken, maar die word dan vervangen door || waarna dit tijdens het parseproces weer word teruggevormt tot |)

Aangezien ik de basisbeginsellen weet van Regex (hetgeen waar bovenstaande preg_split mee is uitgerust) vraag ik dus jullie hulp. Mocht je nog een hele goede documentatie hebben (waarna ik zelf ook al heb gezocht, maar niet gevonden) waarin soortgelijke problemen ook worden aangepakt hoor ik het graag.

(http://82.171.22.30/derek/test.php zie hier het verschil tussen de preg_split en mijn zelfgemaakte functie... preg_split is tot 60 keer sneller! alleen werkt niet geheel goed (zie het probleem hierboven))

Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

kun je niet explode gebruiken nadat je de karakters ge-escaped hebt?

Dus eerst escapen en je || even vervangen door een ander teken, daarna explode, tekens terugzetten.

Misschien is het sneller.

Ik zou sowieso bij standaard php functies blijven, aangezien die gecompileerd zijn. (en dus sneller)

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

Anoniem: 166653

Topicstarter
JKVA schreef op maandag 06 maart 2006 @ 15:52:
kun je niet explode gebruiken nadat je de karakters ge-escaped hebt?

Dus eerst escapen en je || even vervangen door een ander teken, daarna explode, tekens terugzetten.

Misschien is het sneller.

Ik zou sowieso bij standaard php functies blijven, aangezien die gecompileerd zijn. (en dus sneller)
Ja daarom vroeg ik het ook hier. Maar al zou ik de || eerst vervangen door een ander teken, zou ik dat andere teken waarin ik het verander weer moeten escapen, en zo blijf je bezig met escapen...

ter verduidelijking ik heb: iets||iets en ik vervang de || door ╝. Stel dat vervolgens iemand het teken ╝ wil gebruiken, word dit vervolgens weer terugveranderd in |.

Dus je moet dan ook weer een workaround vinden voor het teken ╝, en dit gaat dus niet echt opschieten.

Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 10-06 16:30

Bosmonster

*zucht*

2 explode's en een foreach loopje?

En die data komt ergens vandaan, gewoon zorgen dat er bij invoer geen | gebruikt mag worden.

Acties:
  • 0 Henk 'm!

Anoniem: 166653

Topicstarter
Bosmonster schreef op maandag 06 maart 2006 @ 16:17:
[...] gewoon zorgen dat er bij invoer geen | gebruikt mag worden.
Dat is juist mijn hele probleem, ik wil dus zorgen dat alle tekens mogen worden gebruikt. In dit fora ga ik toch ook niet bepaalde tekens vervangen door niets, omdat anders mijn script gaat hangen. En met 2 explodes hoe had je dat dan in gedachten?

Edit:
Dus eigenlijk wil ik dus net zoiets als dat je in PHP doet met hetvolgende:
code:
1
echo"iets \"gequote tekst\" enzo";


PHP negeerd vervolgens de " en ziet dat dus niet als einde, waardoor het dus niet vastloopt, en de output hetvolgende krijgt:
code:
1
iets "gequote tekst" enzo
wat ik dus probeer is:
code:
1
var1=iets||en hier mag ook tekst|||var2=iets
wat dan hetvolgende word:
code:
1
2
var1=iets|en hier mag ook tekst|
var2=iets

[ Voor 36% gewijzigd door Anoniem: 166653 op 06-03-2006 16:25 ]


Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 08:19
Generiek escape / escapedSplit paartje functies gemaakt. 't is aan de lange kant zo op een forum maar wel redelijk expliciet becommentarieert.
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
 * escapes all characters in input that are present in
 * str strChars. The escapecharacter str escapeChar is set to \ 
 * by default but may be set to any single character. When
 * multiple characters are specified as escape charcter, only the
 * first is used.
 * If input is an array, all values of the array will be escaped recursively
 */
function escape($input, $strChars, $escapeChar='\\') {
    $escaped = array();

    //operate arrays recursively
    if (is_array($input)) {
        foreach ($input as $key=>$value) {
            $input[$key] = escape($value, $strChars, $escapeChar);
        }
        return $input;
    }

    //only use first char of scape char string
    $escapeChar = $escapeChar[0];

    //Always escape escape char first
    $input = str_replace($escapeChar, $escapeChar .$escapeChar, $input);
    array_push($escaped, $escapeChar);

    //escape specified chars
    $numChars = strlen($strChars);
    for ($i=0; $i<$numChars; $i++) {

        $char = $strChars[$i];

        //never escape twice
        if (!in_array($char, $escaped)) { 
            $input = str_replace($char, $escapeChar .$char, $input);
            array_push($escaped, $char);
        }
    }

    return $input;
}


/**
 * splits str string in pieces that are delimited by unescaped
 * occurences of str char.
 */
function escapedSplit($string, $char, $escapeChar='\\') {

    $escapeChar = $escapeChar[0];
    $output = array();

    $offsetStart = 0;
    $partStart = 0;

    //find splitcharacters in string
    while(($pos = strpos($string, $char, $offsetStart)) !== FALSE) {
        $unescaped = TRUE;

        //determine escaped status
        for ($i=$pos-1; $string[$i] == $escapeChar; $i--) {
            $unescaped = !$unescaped;
        }

        //split if unescaped
        if ($unescaped) {
            $partLength = $pos - $partStart;
            array_push($output, substr($string, $partStart, $partLength));
            $partStart = $pos+1;
        }
        $offsetStart = $pos+1;
    }
    
    //last part
    array_push($output,substr($string, $partStart));

    //unescape pieces
    $output = str_replace($escapeChar .$char, $char, $output);
    $output = str_replace($escapeChar .$escapeChar, $escapeChar, $output);

    return $output;
}

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

Anoniem: 166653

Topicstarter
T-MOB schreef op maandag 06 maart 2006 @ 19:02:
Generiek escape / escapedSplit paartje functies gemaakt. 't is aan de lange kant zo op een forum maar wel redelijk expliciet becommentarieert.
[...]
http://82.171.22.30/derek/test.php

De onderste is dus van die code die ook op PHP.net staat en al eerder heb uitgeprobeerd. Deze code lijkt iets verkeerd te doen (of ik ben het zelf)...

PHP:
1
$test3 = escapedSplit($string, "|", "|");


Dat heb ik op het moment waarbij $string hierboven staat aangegeven (op mijn server gebruik ik overigens een andere string). Zoals je ziet split deze geheel verkeerd lijkt wel (ook al backslash ik de | omdat het anders misschien door PHP verkeerd wordt beoordeeld).

Dus doe ik nou wat fout, of wil dat script niet werken?

[ Voor 88% gewijzigd door Anoniem: 166653 op 06-03-2006 19:44 ]


Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 08:19
Anoniem: 166653 schreef op maandag 06 maart 2006 @ 19:19:
[...]

Dus doe ik nou wat fout, of wil dat script niet werken?
Hmm, je hebt gelijk. Het gaat mis als het split character hetzelfde is als het escape character. Het script split dan op de het eerste teken in plaats van het laatste. Dat moet wel aan te passen zijn :) is aangepast.

En dan dus gewoon
PHP:
1
escapedSplit($string, '|', '|');



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
40
41
42
43
44
45
46
/**
 * splits str string in pieces that are delimited by unescaped
 * occurences of str char.
 */
function escapedSplit($string, $char, $escapeChar='\\') {

    $escapeChar = $escapeChar[0];
    $output = array();

    $offsetStart = 0;
    $partStart = 0;

    //enable lookahead when escapechar equals splitchar
    $lookAhead = ($char == $escapeChar);

    //find splitcharacters in string
    while(($pos = strpos($string, $char, $offsetStart)) !== FALSE) {

        //skip iteration when following char is splitchar
        if ($lookAhead && $string[$pos+1] == $char) { $offsetStart = $pos+2; continue; }

        $unescaped = TRUE;

        //determine escaped status
        for ($i=$pos-1; $string[$i] == $escapeChar; $i--) {
            $unescaped = !$unescaped;
        }

        //split if unescaped
        if ($unescaped) {
            $partLength = $pos - $partStart;
            array_push($output, substr($string, $partStart, $partLength));
            $partStart = $pos+1;
        }
        $offsetStart = $pos+1;
    }
    
    //last part
    array_push($output,substr($string, $partStart));

    //unescape entries
    $output = str_replace($escapeChar .$char, $char, $output);
    $output = str_replace($escapeChar .$escapeChar, $escapeChar, $output);

    return $output;
}

[ Voor 72% gewijzigd door T-MOB op 06-03-2006 19:59 ]

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

Anoniem: 166653

Topicstarter
Vaag ik dacht dat het werkte, maar als men hetvolgende verstuurd \\| (waarbij de originele niet geescapede char \| was) geeft hij alleen maar | weer.... ook al maak je er \\\| van.

Ok met jou nieuwe script al doe ik: |||||| krijg ik maar || te zien in het uiteindelijke parse resultaat... maar ik kijk nog even verder

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
40
41
function escapedSplit($string, $char, $escapeChar='\\') {

    $escapeChar = $escapeChar[0];
    $output = array();

    $offsetStart = 0;
    $partStart = 0;

    //enable lookahead when escapechar equals splitchar
    $lookAhead = ($char == $escapeChar);

    //find splitcharacters in string
    while(($pos = strpos($string, $char, $offsetStart)) !== FALSE) {

        if ($lookAhead && $string[$pos+1] == $char) { $offsetStart = $pos+1; continue; }

        //skip iteration when following 
        $unescaped = TRUE;

        //determine escaped status
        for ($i=$pos-1; $string[$i] == $escapeChar; $i--) {
            $unescaped = !$unescaped;
        }

        //split if unescaped
        if ($unescaped) {
            $partLength = $pos - $partStart;
            array_push($output, substr($string, $partStart, $partLength));
            $partStart = $pos+1;
        }
        $offsetStart = $pos+1;
    }
    
    //last part
    array_push($output,substr($string, $partStart));

    //unescape entries
    $output = str_replace($escapeChar .$char, $char, $output);

    return $output;
}


Zo werkt hij helemaal ;)

Onwijs bedankt!!!!!

[ Voor 186% gewijzigd door Anoniem: 166653 op 06-03-2006 19:51 ]


Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 08:19
Anoniem: 166653 schreef op maandag 06 maart 2006 @ 19:45:
Vaag ik dacht dat het werkte, maar als men hetvolgende verstuurd \\| (waarbij de originele niet geescapede char \| was) geeft hij alleen maar | weer.... ook al maak je er \\\| van.

Ok met jou nieuwe script al doe ik: |||||| krijg ik maar || te zien in het uiteindelijke parse resultaat... maar ik kijk nog even verder
[..]
Zo werkt hij helemaal ;)

Onwijs bedankt!!!!!
Ah, je had het dubbel unescapen bij een gelijk split als escape character ook gezien :). In plaats van de regel weghalen kun je trouwens beter een van de regels conditioneel uitvoeren. Zoals je het nu hebt opgelost werkt de functie namelijk alleen nog maar als het split-karakter hetzelfde is als het escape karakter.
PHP:
37
38
39
40
41
42
    //unescape entries
    $output = str_replace($escapeChar .$char, $char, $output);
    
    if ($escapeChar != $char) {
        $output = str_replace($escapeChar .$escapeChar, $escapeChar, $output);
    }

Regeren is vooruitschuiven

Pagina: 1