Domanda

Ok questo è davvero difficile da spiegare in inglese, quindi mi limiterò a dare un esempio.

Ho intenzione di avere stringhe nel seguente formato:

key-value;key1-value;key2-...

e ho bisogno di estrarre i dati da un array

array('key'=>'value','key1'=>'value1', ... )

Ho intenzione di utilizzare regexp per raggiungere (la maggior parte) questa funzionalità, e ho scritto questa espressione regolare:

/^(\w+)-([^-;]+)(?:;(\w+)-([^-;]+))*;?$/

a lavorare con preg_match e questo codice:

for ($l = count($matches),$i = 1;$i<$l;$i+=2) {
    $parameters[$matches[$i]] = $matches[$i+1];
}

Tuttavia regexp restituisce ovviamente solo 4 backreference - prima e dell'ultima coppia di valori chiave della stringa di input. C'è un modo per aggirare questo? So che posso usare regex solo per testare la correttezza della stringa e utilizzare explode di PHP in loop con risultati perfetti, ma sono davvero curioso di sapere se è possibile con le espressioni regolari.

In breve, devo catturare un numero arbitrario di queste coppie key-value; in una stringa mediante espressioni regolari.

È stato utile?

Soluzione

È possibile utilizzare un lookahead per convalidare l'input mentre si estraggono le partite:

/\G(?=(?:\w++-[^;-]++;?)++$)(\w++)-([^;-]++);?/

(?=(?:\w++-[^;-]++;?)++$) è la parte di convalida. Se l'ingresso non è valido, la corrispondenza non riuscirà subito, ma il lookahead viene comunque valutata ogni volta che viene applicata l'espressione regolare. Al fine di mantenere esso (insieme al resto della regex) in sincronia con le coppie chiave-valore, che ho usato \G di ancorare ogni partita al punto in cui la partita si è conclusa precedente.

In questo modo, se il lookahead riesce per la prima volta, è garantito per avere successo ogni volta successiva. Ovviamente non è così efficace come potrebbe essere, ma che probabilmente non sarà un problema -. Solo il test può dire con certezza

Se il lookahead fallisce, preg_match_all() restituirà zero (false). Se riesce, le partite saranno restituiti in un array di array:. Uno per le coppie di valori-chiave completi, uno per le chiavi, uno per i valori

Altri suggerimenti

regex è uno strumento potente, ma a volte, la sua non è l'approccio migliore.

$string = "key-value;key1-value";
$s = explode(";",$string);
foreach($s as $k){
    $e = explode("-",$k);
    $array[$e[0]]=$e[1];
}
print_r($array);

preg_match_all() . Forse qualcosa di simile:

$matches = $parameters = array();
$input = 'key-value;key1-value1;key2-value2;key123-value123;';

preg_match_all("/(\w+)-([^-;]+)/", $input, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
   $parameters[$match[1]] = $match[2];
}

print_r($parameters);

EDIT:

per convalidare primo luogo se la stringa di input è conforme al modello, quindi basta usare:

if (preg_match("/^((\w+)-([^-;]+);)+$/", $input) > 0) {
    /* do the preg_match_all stuff */
}       

EDIT2: il punto e virgola finale è facoltativo

if (preg_match("/^(\w+-[^-;]+;)*\w+-[^-;]+$/", $input) > 0) {
    /* do the preg_match_all stuff */
}       

No. le partite più recenti sovrascrivono le partite più anziani. Forse l'argomento limit di explode() sarebbe utile quando esplodono.

che dire di questa soluzione:

$samples = array(
    "good" => "key-value;key1-value;key2-value;key5-value;key-value;",
    "bad1" => "key-value-value;key1-value;key2-value;key5-value;key-value;",
    "bad2" => "key;key1-value;key2-value;key5-value;key-value;",
    "bad3" => "k%ey;key1-value;key2-value;key5-value;key-value;"
);

foreach($samples as $name => $value) {
    if (preg_match("/^(\w+-\w+;)+$/", $value)) {
        printf("'%s' matches\n", $name);
    } else {
        printf("'%s' not matches\n", $name);
    }
}

Non credo che si può fare sia la validazione e l'estrazione dei dati con un unico regexp, come avete bisogno di ancore (^ e $) per la validazione e preg_match_all() per i dati, ma se si utilizza ancore con preg_match_all() sarà soltanto il ritorno l'ultimo set abbinato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top