PHP - Iteration von Zeichenfolgen


119

Gibt es eine gute Möglichkeit, die Zeichen einer Zeichenfolge zu durchlaufen? Ich möchte in der Lage sein zu tun foreach, array_map, array_walk, array_filterusw. auf den Zeichen einer Zeichenkette.

Typ Casting / Jonglieren brachte mich nicht weiter (setzen Sie den gesamten String als ein Element des Arrays), und die beste Lösung, die ich gefunden habe, ist einfach die Verwendung einer for-Schleife zum Erstellen des Arrays. Es fühlt sich an, als ob es etwas Besseres geben sollte. Ich meine, wenn Sie darauf indizieren können, sollten Sie dann nicht auch iterieren können?

Das ist das Beste, was ich habe

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);

Gibt es entweder:

A) Eine Möglichkeit, die Zeichenfolge iterierbar zu machen
B) Eine bessere Möglichkeit, das Zeichenarray aus der Zeichenfolge zu erstellen (und wenn ja, wie wäre es mit der anderen Richtung?)

Ich habe das Gefühl, dass mir hier etwas Offensichtliches fehlt.


Vielleicht sollten Sie mehr darüber sagen, was Sie erreichen möchten ... es scheint, als gäbe es einen besseren Weg, dies mit normalen Zeichenfolgenoperationen zu tun.
Vinay Pai

1
Ich habe hier kein wirkliches Ziel. Nur eine Neugier, mit der ich gespielt habe. Es schien seltsam, dass Sie nicht iterieren können, obwohl Sie Zeichenfolgen indizieren können. Ich war nicht in der Lage, mir sinnvolle Beispielverwendungen auszudenken, aber ich würde immer noch gerne wissen, ob es eine Möglichkeit gibt, die Zeichenfolgenzeichen zu iterieren, ohne explizit ein Zeichenarray zu erstellen
jon_darkstar

das ist aber ein guter Punkt, offensichtlich sind meine Beispiele ziemlich flach. dh - meistens alles, was Sie array_filterin diesem Sinne tun würden, könnte besser mit
String-

Das Lösen von projecteuler.net/problem=20 könnte ein beispielhafter (wenn auch etwas erfundener) Anwendungsfall sein.
Nick Edwards

Ein Hinweis zu ($ i = 0; $ i <strlen ($ s); $ i ++) Ich würde die strlen ($ s) vor dem Schleifen in einer Variablen speichern. Auf diese Weise rufen Sie strlen () nicht mehr als auf 1 Mal
Amin

Antworten:


176

Schritt 1: Konvertieren Sie die Zeichenfolge mithilfe der str_splitFunktion in ein Array

$array = str_split($your_string);

Schritt 2: Durchlaufen Sie das neu erstellte Array

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

Sie können die PHP-Dokumente für weitere Informationen überprüfen: str_split


hah wow Ja das ist es. und natürlich kann implodieren die andere Richtung tun. Ich werde dies bald akzeptieren, es sei denn, jemand kann einen Weg zeigen, die Iteration direkt auf dem Stich
durchzuführen

@jon_darkstar Ich kenne Ihre Anwendung nicht, aber beachten Sie, dass jeder Eintrag in einem Array einen erheblichen Overhead hat (4 Byte IIRC). Überspringen Sie das, es ist "ziemlich" viel mehr: 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.- str_splitKann also nicht mit Unicode arbeiten
Happy

84

Iterierte Zeichenfolge:

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

7
Dies scheint eine bessere Antwort zu sein, da es die Frage beantwortet - dh wie man über einen String iteriert und nicht in ein Array konvertiert.
Robin Andrews

2
LOL !!!!! Alles @OmarTariq. Dies ist viel effizienter als die Antwort.
0x476f72616e

5
Beachten Sie nur, dass Sie strlen()jede Iteration aufrufen . Keine schreckliche Sache, da PHP die Länge vorberechnet hat, aber immer noch ein Funktionsaufruf. Wenn Sie Geschwindigkeit benötigen, speichern Sie diese besser in einer Variablen, bevor Sie die Schleife starten.
Vilx

2
Dies ist nicht gut für Multibyte-Strings, da wir hier den Byte-Offset erhalten, kein Symbol
immer

2
@OmarTariq "Dies ist die Antwort. Was ist los mit der Welt?" .... Das Falsche an der Welt ist, dass die Welt andere Sprachen als Englisch hat. Diese Funktion wird, wie immer gesagt, die Bytes in der Zeichenfolge iterieren, nicht die Zeichen.
Buchhalter

20

Wenn Ihre Zeichenfolgen in Unicode sind, sollten Sie preg_splitmit verwenden/u Modifikator verwenden

Aus Kommentaren in der PHP-Dokumentation:

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

1
Ist für Multibyte-Strings mb_splitzuverlässiger.
Élektra

12

Sie können auch einfach wie ein Array auf $ s1 zugreifen, wenn Sie nur darauf zugreifen müssen:

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

6

Ausgehend von der Antwort von @SeaBrightSystems können Sie Folgendes versuchen:

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

Ich bin anderer Meinung, diese Antwort bietet einen Mehrwert und gibt ein funktionierendes Beispiel dafür, wie str_split in einer PHP-Anwendung funktionieren könnte. @SeaBrightSystems verlinkt nur auf die Dokumentation, was manchmal nicht so hilfreich ist, wenn eine Person anhand eines Beispiels versucht, die Funktionsweise einer Funktion zu ermitteln. Andernfalls wären die meisten SO-Antworten nur Links zu php.net
kurdtpage

6

Für diejenigen, die nach dem schnellsten Weg suchen, um über Strings in PHP zu iterieren, habe ich einen Benchmark-Test vorbereitet.
Die erste Methode, bei der Sie direkt auf Zeichenfolgenzeichen zugreifen, indem Sie ihre Position in Klammern angeben und Zeichenfolgen wie ein Array behandeln:

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

Ich selbst dachte, Letzteres sei die schnellste Methode, aber ich habe mich geirrt.
Wie bei der zweiten Methode (die in der akzeptierten Antwort verwendet wird):

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

Diese Methode wird schneller sein, da wir ein reales Array verwenden und nicht davon ausgehen, dass es sich um ein Array handelt.

Das Aufrufen der letzten Zeile jeder der oben genannten Methoden für 1000000Zeiten führt zu folgenden Benchmarking-Ergebnissen:

Verwenden von string [i]
0.24960017204285 Seconds

Mit str_split
0.18720006942749 Seconds

Was bedeutet, dass die zweite Methode viel schneller ist.


3

Hmm ... Es besteht keine Notwendigkeit, Dinge zu komplizieren. Die Grundlagen funktionieren immer gut.

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

Vorwärtsrichtung:

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

Ausgänge: abcdef

Rückwärtsrichtung:

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

Ausgänge: 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;
}

Ich bin überrascht, dass diese Antwort nur 1 positive Bewertung erhalten hat :( Dies ist die zuverlässigste Antwort hier
Buchhalter م

1

Die meisten Antworten haben nicht englische Zeichen vergessen !!!

strlenzählt BYTES, nicht Zeichen, deshalb funktioniert es und seine Geschwisterfunktionen funktionieren gut mit englischen Zeichen, da englische Zeichen sowohl in UTF-8- als auch in ASCII-Codierungen in 1 Byte gespeichert sind, müssen Sie die Multibyte-Zeichenfolgenfunktionen verwenden mb_*

Dies funktioniert mit jedem in codierten ZeichenUTF-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);
}

Dies gibt aus

string(1) "a"
string(1) "b"
string(1) "c"
string(1) "d"
string(2) "أ"
string(2) "ب"
string(2) "ت"
string(2) "ث"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.