[PHP] Zoeken en vervangen met preg

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Hallo allen,

Ik heb de volgende voorbeeld string:
PHP:
1
2
3
4
5
<?php
$str_1 = 'Foo,1a,2b,3c;Schoenmaat,38,41,45,48;Bar,1,2,3,4;Kleur,Blauw,Oranje,Paars;Abc,A,B,D';
$str_2 = 'Kleur,Groen,Oranje,Paars,Zwart;Schoenmaat,36,40,45,48';
$str_1 = 'Foo,1a,2b,3c;Schoenmaat,36,40,45,48;Bar,1,2,3,4;Kleur,Oranje,Paars,Zwart;Abc,A,B,D';
?>


De structuur van de strings is als volgt: Het eerste woord is de naam van de waarden die erachter staan en gescheiden met een , met achter de laatste waarde een;. Dit kan 1 of meerdere keren achter elkaar staan in 1 string.

Wat wil ik bereiken: $str_1 moet geupdate worden met de waarden van $str_2. In $str_2 staan de nieuwe waarden voor elk veld dat is veranderd. Het eindresultaat is te zien in $str_3.

Wat heb ik tot nu toe:
PHP:
1
2
3
<?php
preg_match_all("/([A-Z]{1}[a-z]*,[_a-zA-Z0-9,]*\;?)*/",   $str_1, $out);
?>


Met als output:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$out:
Array
(
    [0] => Array
        (
            [0] => Foo,1a,2b,3c;Schoenmaat,38,41,45,48;Bar,1,2,3,4;Kleur,Blauw,Oranje,Paars;Abc,A,B,D
            [1] => 
        )

    [1] => Array
        (
            [0] => Abc,A,B,D
            [1] => 
        )

)


Uiteindelijk denk ik dat ik preg_replace() kan gebruiken. Maar ik heb preg nog steeds niet goed door (elke keer als je het nodig hebt zoek je een tut, maak je wat je wil en vergeet je het weer), dus probeer het stap voor stap.

Wie kan mij aub verder op weg helpen?

Alvast bedankt!

Groeten,
Robert

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Deel het op in subproblemen, en haal er vooral geen regex bij.

Eerste stappen: explode() op ';', en loop door het resultaat waarbij je nog een keer explode op ',' en het eerste element als key voor een array gebruikt.

{signature}


Acties:
  • 0 Henk 'm!

  • Tharulerz
  • Registratie: April 2009
  • Laatst online: 10-04 05:16
Wat voutloos zegt.

En als je dit systeem zelf kan kiezen, gebruik dan tussen je eerste variabele naam en zijn waarden een ':' en niet een ',' , dat maakt het nog gemakkelijker

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Bedankt voor de ideeën.

Ik was inderdaad veel te moeilijk bezig. Ik heb nu een aantal x foreach en een explode gebruikt. Een deel van de code is dit:
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
// Voorbeeld String
$str = 'Schoenmaat,38,39,40,41,46,48;Kleur,Blue,Green,Red,White;Iets,Anders;Nog,Iets Anders;Abc,A'; 
            
            // Get Origional Attributes         
            $attribute_list_org_temp = explode(';',$str);

/*
Array $attribute_list_org_temp
(
    [0] => Schoenmaat,38,39,40,41,46,48
    [1] => Kleur,Blue,Green,Red,White
    [2] => Iets,Anders
    [3] => Nog,Iets Anders
    [4] => Abc,A
)
*/
            
            // Create Array from Origional Attributes
            foreach($attribute_list_org_temp as $key => $value ) {
                $temp[] = explode(',', $value, 2);
            }
/*
Array $temp
(
    [0] => Array
        (
            [0] => Schoenmaat
            [1] => 38,39,40,41,46,48
        )

    [1] => Array
        (
            [0] => Kleur
            [1] => Blue,Green,Red,White
        )

    [2] => Array
        (
            [0] => Iets
            [1] => Anders
        )

    [3] => Array
        (
            [0] => Nog
            [1] => Iets Anders
        )

    [4] => Array
        (
            [0] => Abc
            [1] => A
        )

)
*/          
            // Recreate Array from Origional Attributes, by Attribute Name
            foreach($temp as $key => $value ) {
                $attribute_list_org[ $value[0] ] = $value[1];   
            }
/*
Array $attribute_list_org
(
    [Schoenmaat] => 38,39,40,41,46,48
    [Kleur] => Blue,Green,Red,White
    [Iets] => Anders
    [Nog] => Iets Anders
    [Abc] => A
)

*/


Kan dit efficiënter/korter?

@Tharulerz: Ik heb hier helaas geen keus en moet me houden aan het format van $str.

Vervolgens doe ik dit om de de Originele waarden met de Nieuwe waarden te synchroniseren:
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
            // Update Origional Attributes with New Values into New Array
            $attribute_list_new = $attribute_list_org;
            foreach($attribute_list_new_values as $key => $value ) {
                if ( $value != '' ) {
                    $attribute_list_new[ $key ] = $value;
                } else {
                    unset( $attribute_list_new[ $key ]);
                }
            }   
/*
Array $attribute_list_new
(
    [Schoenmaat] => 38,40,46
    [Kleur] => Blue,Green,Red,White
    [Iets] => Anders
    [Nog] => Iets Anders
)

*/
            
            // Create Attribute String with New Values
            $attribute_list_new_str = '';
            foreach($attribute_list_new as $key => $value ) {   
                if ( $attribute_list_new_str != '' ) {
                    $attribute_list_new_str .= ';';
                }
                $attribute_list_new_str .= $key.','.$value;
            }
/*
$attribute_list_new_str: Schoenmaat,38,40,46;Kleur,Blue,Green,Red,White;Iets,Anders;Nog,Iets Anders;
*/


Ook voor dit deel de vraag: Kan het korter/efficiënter?

Acties:
  • 0 Henk 'm!

Verwijderd

Waarom? Heb je last van performanceproblemen?

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Verwijderd schreef op zaterdag 11 december 2010 @ 09:01:
Waarom? Heb je last van performanceproblemen?
Nee, maar aangezien er zoveel standaard PHP functies zijn en ik ze niet allemaal ken, kan het best zo zijn dat dit veel eenvoudiger of beter kan. :)

Acties:
  • 0 Henk 'm!

  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Zo is het iets korter en gebruik je een loop minder:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

$selector = 'Foo,1a,2b,3c;Schoenmaat,38,41,45,48;Bar,1,2,3,4;Kleur,Blauw,Oranje,Paars;Abc,A,B,D';
$parts = explode(';', $selector);
$result = array();
foreach($parts as $part){
    $items = explode(',', $part);
    // eerste element in de array is de name
    $name = array_shift($items);
    $result[$name] = $items;
}
echo '<pre>';
print_r($result);

Acties:
  • 0 Henk 'm!

  • ID-College
  • Registratie: November 2003
  • Laatst online: 15:55
Verwijderd schreef op zaterdag 11 december 2010 @ 08:51:
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
            // Update Origional Attributes with New Values into New Array
            $attribute_list_new = $attribute_list_org;
            foreach($attribute_list_new_values as $key => $value ) {
                if ( $value != '' ) {
                    $attribute_list_new[ $key ] = $value;
                } else {
                    unset( $attribute_list_new[ $key ]);
                }
            }   
/*
Array $attribute_list_new
(
    [Schoenmaat] => 38,40,46
    [Kleur] => Blue,Green,Red,White
    [Iets] => Anders
    [Nog] => Iets Anders
)

*/
            
            // Create Attribute String with New Values
            $attribute_list_new_str = '';
            foreach($attribute_list_new as $key => $value ) {   
                if ( $attribute_list_new_str != '' ) {
                    $attribute_list_new_str .= ';';
                }
                $attribute_list_new_str .= $key.','.$value;
            }
/*
$attribute_list_new_str: Schoenmaat,38,40,46;Kleur,Blue,Green,Red,White;Iets,Anders;Nog,Iets Anders;
*/


Ook voor dit deel de vraag: Kan het korter/efficiënter?
Mocht hierboven niet werken zoals je wilt, dan zou ik het iets korter opschrijven:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
            // Update Origional Attributes with New Values into New Array
            $attribute_list_new = $attribute_list_org;
            foreach($attribute_list_new_values as $key => $value ) {
                !empty($value) ? $attribute_list_new[$key] = $value : unset($attribute_list_new[ $key ]);
            }
            
            // Create Attribute String with New Values
            $attribute_list_new_str = NULL;
            foreach($attribute_list_new as $key => $value ) {   
                !empty($attribute_list_new_str) ? $attribute_list_new_str .= ';';
                                $attribute_list_new_str .= $key.','.$value;
            }

[ Voor 0% gewijzigd door ID-College op 11-12-2010 15:10 . Reden: laatste was geen if/else statement... ]


Acties:
  • 0 Henk 'm!

  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 19:39
ID-College schreef op zaterdag 11 december 2010 @ 15:07:
[...]

Mocht hierboven niet werken zoals je wilt, dan zou ik het iets korter opschrijven:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
            // Update Origional Attributes with New Values into New Array
            $attribute_list_new = $attribute_list_org;
            foreach($attribute_list_new_values as $key => $value ) {
                !empty($value) ? $attribute_list_new[$key] = $value : unset($attribute_list_new[ $key ]);
            }
            
            // Create Attribute String with New Values
            $attribute_list_new_str = NULL;
            foreach($attribute_list_new as $key => $value ) {   
                !empty($attribute_list_new_str) ? $attribute_list_new_str .= ';';
                                $attribute_list_new_str .= $key.','.$value;
            }
Waarom? Ja, het scheelt een paar regels, maar wat maakt dat uit? (Ik snap in elk geval niet hoe korter opschrijven een oplossing is als het niet zou werken zoals TS wil.) Nu heb je langere en moeilijker leesbare regels (sowieso heb je dan nog steeds "$attribute_list_new_str .=" onnodig twee keer in die tweede foreach). Het veranderen naar null/empty is nergens voor nodig en introduceert zelfs kleine nieuwe slordigheden (concatenatie van null en een string).

Wel kun je de nieuwe string tegelijk met of (als de array niet nodig is) in plaats van de array vullen, wat weer een foreach scheelt. Voor strings als in het voorbeeld zul je dat verschil ook niet merken, maar het lijkt me toch zinniger dan krampachtig elke if/else omschrijven naar een ternary-geval.

Acties:
  • 0 Henk 'm!

  • Cousin Boneless
  • Registratie: Juni 2008
  • Laatst online: 28-02 12:55
Het probleem met dit soort eigen notaties is dat men er geen rekening mee houdt dat control-characters in de data kunnen voorkomen. Ik zou hiervoor JSON gebruiken. Klein beetje overhead, maar tenminste goed gedocumenteerd en met een PHP implementatie, zodat je je dit gepriegel kan besparen.
Dus ik weet niet of het argument dat je het hier mee moet doen zwaarwegend is, maar ik zou er niet zo snel genoegen mee nemen.. een exportje aanpassen is veel makkelijker dan troep moeten importeren.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Cousin Boneless schreef op zondag 12 december 2010 @ 13:14:
Het probleem met dit soort eigen notaties is dat men er geen rekening mee houdt dat control-characters in de data kunnen voorkomen. Ik zou hiervoor JSON gebruiken. Klein beetje overhead, maar tenminste goed gedocumenteerd en met een PHP implementatie, zodat je je dit gepriegel kan besparen.
Dus ik weet niet of het argument dat je het hier mee moet doen zwaarwegend is, maar ik zou er niet zo snel genoegen mee nemen.. een exportje aanpassen is veel makkelijker dan troep moeten importeren.
Het is voor een aanpassing/toevoeging in een standaard webshop component, dat regelmatig geupdate wordt. Mijn toevoeging zal ook maar 1 record per keer aanpassen en ik weet dat er in dit geval geen control-characters in de data zullen voorkomen. Maar je hebt er zeker gelijk in dat dit netter en beter met JSON opgelost had kunnen worden.
orf schreef op zaterdag 11 december 2010 @ 14:57:
Zo is het iets korter en gebruik je een loop minder:

PHP:
1
2
3
4
5
6
7
8
9
10
11
<?php

$selector = 'Foo,1a,2b,3c;Schoenmaat,38,41,45,48;Bar,1,2,3,4;Kleur,Blauw,Oranje,Paars;Abc,A,B,D';
$parts = explode(';', $selector);
$result = array();
foreach($parts as $part){
    $items = explode(',', $part);
    // eerste element in de array is de name
    $name = array_shift($items);
    $result[$name] = $items;
}
Deze zal ik zeker gebruiken.
Raynman schreef op zaterdag 11 december 2010 @ 21:11:
[...]
sowieso heb je dan nog steeds "$attribute_list_new_str .=" onnodig twee keer in die tweede foreach
Hoe kan ik de 2e foreach nog inkorten zodat "$attribute_list_new_str .=" niet onnodig 2x wordt gebruikt?

Acties:
  • 0 Henk 'm!

  • TJHeuvel
  • Registratie: Mei 2008
  • Niet online
Verwijderd schreef op maandag 13 december 2010 @ 03:55:
Het is voor een aanpassing/toevoeging in een standaard webshop component, dat regelmatig geupdate wordt. Mijn toevoeging zal ook maar 1 record per keer aanpassen en ik weet dat er in dit geval geen control-characters in de data zullen voorkomen. Maar je hebt er zeker gelijk in dat dit netter en beter met JSON opgelost had kunnen worden.
Ik hoop niet dat dit zo een database ingaat, ipv het eens goed te normaliseren?

[ Voor 14% gewijzigd door TJHeuvel op 13-12-2010 09:15 ]

Freelance Unity3D developer

Pagina: 1