PHP: itera sui caratteri della stringa


120

C'è un bel modo per iterare sui caratteri di una stringa? Mi piacerebbe essere in grado di fare foreach, array_map, array_walk, array_filterecc sui caratteri di una stringa.

Il tipo casting / juggling non mi ha portato da nessuna parte (metti l'intera stringa come un elemento dell'array) e la migliore soluzione che ho trovato è semplicemente usare un ciclo for per costruire l'array. Sembra che dovrebbe esserci qualcosa di meglio. Voglio dire, se puoi indicizzarlo non dovresti essere in grado di iterare anche tu?

Questo è il meglio che ho

function stringToArray($s)
{
    $r = array();
    for($i=0; $i<strlen($s); $i++) 
         $r[$i] = $s[$i];
    return $r;
}

$s1 = "textasstringwoohoo";
$arr = stringToArray($s1); //$arr now has character array

$ascval = array_map('ord', $arr);  //so i can do stuff like this
$foreach ($arr as $curChar) {....}
$evenAsciiOnly = array_filter( function($x) {return ord($x) % 2 === 0;}, $arr);

C'è o:

A) Un modo per rendere la stringa iterabile
B) Un modo migliore per costruire l'array di caratteri dalla stringa (e se è così, che ne dici dell'altra direzione?)

Mi sento come se mi mancasse qualcosa di ovvio qui.


Forse dovresti dire di più su ciò che stai cercando di realizzare ... sembra che potrebbe esserci un modo migliore per farlo usando le normali operazioni sulle stringhe.
Vinay Pai

1
non hai un vero obiettivo qui. solo una curiosità con cui stavo giocando. Sembrava strano che anche se puoi indicizzare su stringhe non puoi iterare. Non riuscivo nemmeno a pensare a esempi di usi significativi, ma vorrei comunque sapere se esiste un modo per iterare sui caratteri delle stringhe senza costruire esplicitamente un array di caratteri
jon_darkstar

questo è un buon punto, ovviamente, i miei esempi sono piuttosto superficiali. cioè, per lo più qualsiasi cosa che faresti array_filterin questo senso potrebbe essere fatto meglio con le funzioni stringa o reg-ex
jon_darkstar

La risoluzione di projecteuler.net/problem=20 potrebbe essere un caso d'uso di esempio (anche se in qualche modo artificioso).
Nick Edwards

una nota, per quanto riguarda for ($ i = 0; $ i <strlen ($ s); $ i ++) Memorizzerei strlen ($ s) in una variabile prima del ciclo, in questo modo non chiamerai strlen () più di 1 volta
Amin

Risposte:


176

Passaggio 1: converti la stringa in un array utilizzando la str_splitfunzione

$array = str_split($your_string);

Passaggio 2: scorrere l'array appena creato

foreach ($array as $char) {
 echo $char;
}

Puoi controllare i documenti PHP per ulteriori informazioni: str_split


ah wow. sì questo è tutto. e naturalmente implodere può fare l'altra direzione. Lo accetterò presto a meno che qualcuno non possa mostrare un modo per eseguire l'iterazione direttamente sul punto
jon_darkstar

@jon_darkstar Non conosco la tua applicazione, ma prendi nota che ogni voce in un array ha un overhead significativo (IIRC di 4 byte). Salta questo, è "abbastanza" molto di più: nikic.github.com/2011/12/12/…
Daan Timmer

str_split() will split into bytes, rather than characters when dealing with a multi-byte encoded string.- Quindi str_splitnon può funzionare con Unicode
Buon

85

Itera stringa:

for ($i = 0; $i < strlen($str); $i++){
    echo $str[$i];
}

7
Questa sembra una risposta migliore perché risponde alla domanda, ovvero come iterare su una stringa invece di "convertire in array".
Robin Andrews

2
LOL !!!!! Tutto @OmarTariq. Questo è molto più efficiente della risposta fornita.
0x476f72616e

5
Tieni presente che stai invocando strlen()ogni iterazione. Non è una cosa terribile, poiché PHP ha la lunghezza precalcolata, ma è comunque una chiamata di funzione. Se hai bisogno di velocità, è meglio salvarla in una variabile prima di avviare il ciclo.
Vilx

2
Questo non va bene per le stringhe multibyte, perché qui stiamo ottenendo un offset di byte, non un simbolo
ogni

2
@OmarTariq "Questa è la risposta. Cosa c'è che non va nel mondo?" .... Il torto del mondo è che il mondo ha altre lingue oltre all'inglese, questa funzione, come hanno detto tutti, itererà i byte nella stringa, non i caratteri.
Commercialista م

20

Se le tue stringhe sono in Unicode dovresti usare preg_splitcon il /umodificatore

Dai commenti nella documentazione di php:

function mb_str_split( $string ) { 
    # Split at all position not after the start: ^ 
    # and not before the end: $ 
    return preg_split('/(?<!^)(?!$)/u', $string ); 
} 

1
Per stringhe multibyte, mb_splitè più affidabile.
Élektra

12

Puoi anche accedere a $ s1 come un array, se devi solo accedervi:

$s1 = "hello world";
echo $s1[0]; // -> h

6

Ampliato dalla risposta di @SeaBrightSystems, potresti provare questo:

$s1 = "textasstringwoohoo";
$arr = str_split($s1); //$arr now has character array

Non sono d'accordo, questa risposta aggiunge valore, fornisce un esempio funzionante di come str_split potrebbe funzionare in un'applicazione PHP. @SeaBrightSystems si limita a collegarsi alla documentazione, che a volte non è così utile quando una persona sta cercando di vedere come può funzionare una funzione, dato un esempio. Altrimenti la maggior parte delle risposte SO sarebbero solo collegamenti a php.net
kurdtpage

6

Per coloro che sono alla ricerca del modo più veloce per iterare su stringhe in php, ho preparato un test di benchmark.
Il primo metodo in cui accedi ai caratteri stringa direttamente specificandone la posizione tra parentesi e trattando la stringa come un array:

$string = "a sample string for testing";
$char = $string[4] // equals to m

Io stesso pensavo che quest'ultimo fosse il metodo più veloce, ma mi sbagliavo.
Come con il secondo metodo (utilizzato nella risposta accettata):

$string = "a sample string for testing";
$string = str_split($string);
$char = $string[4] // equals to m

Questo metodo sarà più veloce perché utilizziamo un array reale e non supponiamo che uno sia un array.

Chiamare l'ultima riga di ciascuno dei metodi sopra per i 1000000tempi porta a questi risultati di benchmarking:

Utilizzando la stringa [i]
0.24960017204285 Seconds

Utilizzando str_split
0.18720006942749 Seconds

Il che significa che il secondo metodo è molto più veloce.


3

Hmm ... Non c'è bisogno di complicare le cose. Le basi funzionano sempre alla grande.

    $string = 'abcdef';
    $len = strlen( $string );
    $x = 0;

Direzione in avanti:

while ( $len > $x ) echo $string[ $x++ ];

Uscite: abcdef

Direzione inversa:

while ( $len ) echo $string[ --$len ];

Uscite: fedcba


2
// Unicode Codepoint Escape Syntax in PHP 7.0
$str = "cat!\u{1F431}";

// IIFE (Immediately Invoked Function Expression) in PHP 7.0
$gen = (function(string $str) {
    for ($i = 0, $len = mb_strlen($str); $i < $len; ++$i) {
        yield mb_substr($str, $i, 1);
    }
})($str);

var_dump(
    true === $gen instanceof Traversable,
    // PHP 7.1
    true === is_iterable($gen)
);

foreach ($gen as $char) {
    echo $char, PHP_EOL;
}

Sono sorpreso che questa risposta abbia ottenuto solo 1 voto positivo :( questa è la risposta più / unica affidabile qui
Accountant م

1

La maggior parte delle risposte ha dimenticato i caratteri non inglesi !!!

strlenconta BYTES, non caratteri, ecco perché è e le sue funzioni di pari livello funzionano bene con i caratteri inglesi, perché i caratteri inglesi sono memorizzati in 1 byte sia nelle codifiche UTF-8 che ASCII, è necessario utilizzare le funzioni stringa multibyte mb_*

Funzionerà con qualsiasi carattere codificato inUTF-8

// 8 characters in 12 bytes
$string = "abcdأبتث";

$charsCount = mb_strlen($string, 'UTF-8');
for($i = 0; $i < $charsCount; $i++){
    $char = mb_substr($string, $i, 1, 'UTF-8');
    var_dump($char);
}

Questo produce

string(1) "a"
string(1) "b"
string(1) "c"
string(1) "d"
string(2) "أ"
string(2) "ب"
string(2) "ت"
string(2) "ث"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.