2015-10-25 18 views
5

Voglio tokenize formattazione stringhe (molto approssimativamente come printf) e penso che mi manca solo un po 'piccolo:PHP: creazione di token, usando un'espressione regolare (per lo più là)

  • % [numero] [uno lettera ctYymd] diventa un token²
  • $ 1 ... $ 10 diventa un token
  • tutto il resto (testo normale) diventa un token.

Sono arrivato abbastanza lontano in the regExp simulator. Sembra che dovrebbe fare:

²aggiornamento: ora utilizzando # invece di%. (meno problemi con i parametri della riga di comando di Windows)

enter image description here

Non fa paura, se ci si concentra sulle tre parti, collegate da tubi (come aut-aut), in modo sostanzialmente è solo tre partite. Dal momento che voglio abbinare dall'inizio alla fine, ho avvolto le cose in /^...%/ e circondato da un gruppo non-matching (?:... che possono ripetere 1 o più volte:

$exp = '/^(?:(%\\d*[ctYymd]+)|([^$%]+)|(\\$\\d))+$/'; 

Ancora la mia fonte non consegna:

$exp = '/^(?:(%\\d*[ctYymd]+)|([^$%]+)|(\\$\\d))+$/'; 
echo "expression: $exp \n"; 

$tests = [ 
     '###%04d_Ball0n%02d$1', 
     '%03d_Ball0n%02x$1%03d_Ball0n%02d$1', 
     '%3d_Ball0n%02d', 
    ]; 

foreach ($tests as $test) 
{ 
    echo "teststring: $test\n"; 
    if(preg_match($exp, $test, $tokens)) 
    { 
     array_shift($tokens); 
     foreach ($tokens as $token) 
      echo "\t\t'$token'\n"; 
    } 
    else 
     echo "not valid."; 
} // foreach 

Ottengo risultati ma: Le partite sono fuori servizio. Il primo [numero]% [lettera] non corrisponde, pertanto, gli altri corrispondono doppia:

expression: /^((%\d*[ctYymd]+)|([^$%]+)|(\$\d))+$/ 
teststring: ###%04d_Ball0n%02d$1 
     '$1' 
     '%02d' 
     '_Ball0n' 
     '$1' 
teststring: %03d_Ball0n%02x$1%03d_Ball0n%02d$1 
not valid.teststring: %3d_Ball0n%02d 
     '%02d' 
     '%02d' 
     '_Ball0n' 
teststring: %d_foobardoo 
     '_foobardoo' 
     '%d' 
     '_foobardoo' 
teststring: Ball0n%02dHamburg%d 
     '%d' 
     '%d' 
     'Hamburg' 

risposta

2

Solution (a cura di OP): Io uso una due leggere variazioni (solo per quanto riguarda 'confezionamento'): in primo luogo per la convalida, poi per la creazione di token, di:

#\d*[ctYymd]+|\$\d+|[^#\$]+ 

RegEx Demo

Codice:

$core = '#\d*[ctYymd]+|\$\d+|[^#\$]+'; 
$expValidate = '/^('.$core.')+$/m'; 
$expTokenize = '/('.$core.')/m'; 

$tests = [ 
     '#3d-', 
     '#3d-ABC', 
     '***#04d_Ball0n#02d$1', 
     '#03d_Ball0n#02x$AwrongDollar', 
     '#3d_Ball0n#02d', 
     'Badstring#02xWrongLetterX' 
    ]; 

foreach ($tests as $test) 
{ 
    echo "teststring: [$test]\n"; 

    if(! preg_match_all($expValidate, $test)) 
    { 
     echo "not valid.\n"; 
     continue; 
    } 
    if(preg_match_all($expTokenize, $test, $tokens)) { 
     foreach ($tokens[0] as $token) 
      echo "\t\t'$token'\n"; 
    } 

} // foreach 

uscita:

teststring: [#3d-] 
     '#3d' 
     '-' 
teststring: [#3d-ABC] 
     '#3d' 
     '-ABC' 
teststring: [***#04d_Ball0n#02d$1] 
     '***' 
     '#04d' 
     '_Ball0n' 
     '#02d' 
     '$1' 
teststring: [#03d_Ball0n#02x$AwrongDollar] 
not valid. 
teststring: [#3d_Ball0n#02d] 
     '#3d' 
     '_Ball0n' 
     '#02d' 
teststring: [Badstring#02xWrongLetterX] 
not valid. 
+1

Won-der-ful! Grazie mille! Per analizzare i miei errori: 'preg_match_all' piuttosto che' preg_match'. Perché: semplicemente sbagliato. E mi salva dalla parentesi esterna non corrispondente. –

+0

Sì, è vero. – anubhava

+0

L'unica cosa che mi manca: non mi urla su stringhe errate, salta semplicemente, 'Badstring% 02xWrongLetterX'. –