PHP - dizge karakterleri üzerinde yineleme


121

Bir dizenin karakterlerini yinelemenin güzel bir yolu var mı? Ben yapabilmek istiyorum foreach, array_map, array_walk, array_filterbir dizenin karakterler vb.

Tür atama / hokkabazlık beni hiçbir yere götürmedi (tüm dizeyi dizinin bir öğesi olarak koyun) ve bulduğum en iyi çözüm, diziyi oluşturmak için bir for döngüsü kullanmaktır. Daha iyi bir şey olmalı gibi geliyor. Demek istediğim, onu indeksleyebiliyorsanız, aynı zamanda yineleme yapabilmeniz gerekmez mi?

Bu sahip olduğum en iyisi

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

Aşağıdakilerden biri var mı:

A) Dizeyi yinelenebilir hale getirmenin bir yolu
B) Karakter dizisini dizeden oluşturmanın daha iyi bir yolu (eğer öyleyse, diğer yöne ne dersiniz?)

Burada bariz bir şeyi kaçırdığımı hissediyorum.


Belki de başarmaya çalıştığınız hakkında daha fazla şey söylemelisiniz ... bunu normal dizgi işlemlerini kullanarak yapmanın daha iyi bir yolu olabilir gibi görünüyor.
Vinay Pai

1
burada gerçek bir amacım yok. sadece oynadığım bir merak. Dizeleri indeksleyebilmenize rağmen yineleyememeniz garip görünüyordu. Anlamlı örnek kullanımları bile düşünemeyecek durumdaydım, ancak yine de açık bir şekilde bir karakter dizisi oluşturmadan karakter dizileri üzerinde yineleme yapmanın bir yolu olup olmadığını bilmek istiyorum
jon_darkstar

bu iyi bir nokta, tabii ki benim örneklerim oldukça sığ. yani - çoğunlukla array_filterbu anlamda yapacağınız her şey string veya reg-ex işlevleriyle daha iyi yapılabilir
jon_darkstar

Projecteuler.net/problem=20 çözümünü çözmek bir örnek (biraz uydurma olsa da) kullanım durumu olabilir.
Nick Edwards

($ i = 0; $ i <strlen ($ s); $ i ++) için bir not 1 kez
Amin

Yanıtlar:


176

Adım 1:str_split işlevi kullanarak dizeyi bir diziye dönüştürün

$array = str_split($your_string);

Adım 2: Yeni oluşturulan dizide döngü yapın

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

Daha fazla bilgi için PHP belgelerine bakabilirsiniz: str_split


hah vay. evet işte bu. ve tabii ki implode diğer yönü de yapabilir. Birisi iterasyonu doğrudan
sokarken

@jon_darkstar Uygulamanızı bilmiyorum, ancak bir dizideki her girişin önemli bir ek yüke (4byte IIRC) sahip olduğunu unutmayın. Bunu atlayın, 'oldukça' daha fazlası: 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_splitUnicode ile çalışamaz
mutlu

86

Yineleme dizesi:

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

7
Bu daha iyi bir cevap gibi görünüyor çünkü soruyu cevaplıyor - yani 'diziye dönüştür' yerine bir dizge üzerinde nasıl yineleme yapılır.
Robin Andrews

2
LOL !!!!! Her şey @OmarTariq. Bu, verilen cevaptan çok daha etkilidir.
0x476f72616e

5
strlen()Her yinelemede aradığınızı unutmayın . PHP'nin uzunluğu önceden hesaplandığı için korkunç bir şey değil, ama yine de bir işlev çağrısı. Hıza ihtiyacınız varsa, döngüye başlamadan önce bunu bir değişkene kaydetmeniz daha iyi olur.
Vilx

2
Bu, çok baytlı dizeler için iyi değil, çünkü burada bir sembol değil, bayt ofset
alıyoruz

2
@OmarTariq "Cevap bu. Dünyanın nesi var?" .... Dünyadaki yanlış, dünyanın İngilizce dışında başka dillere sahip olmasıdır, bu işlev her zaman söylendiği gibi karakterleri değil dizedeki baytları yineleyecektir.
Muhasebeci,

20

Dizeleriniz Unicode ise, değiştirici preg_splitile kullanmalısınız/u

Php belgelerindeki yorumlardan:

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

1
Çok baytlı dizeler mb_splitiçin daha güvenilirdir.
Élektra

12

Yalnızca erişmeniz gerekiyorsa, bir dizi gibi $ s1'e de erişebilirsiniz:

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

6

@SeaBrightSystems yanıtından genişletilmiş, şunu deneyebilirsiniz:

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

Katılmıyorum, bu cevap değer katıyor, str_split'in bir PHP uygulamasında nasıl çalışabileceğine dair çalışan bir örnek veriyor. @SeaBrightSystems sadece dokümantasyona bağlanır, bu bazen bir kişi bir fonksiyonun nasıl çalıştığını görmeye çalışırken o kadar da yardımcı olmaz. Aksi takdirde çoğu SO cevabı sadece
php.net'e

6

Php'de dizeleri yinelemenin en hızlı yolunu arayanlar için, bir kıyaslama testi hazırladım.
Dize karakterlerine, konumunu parantez içinde belirterek ve dizeyi bir dizi gibi ele alarak doğrudan eriştiğiniz ilk yöntem:

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

Ben de ikincisinin en hızlı yöntem olduğunu düşündüm, ama yanılmışım.
İkinci yöntemde olduğu gibi (kabul edilen cevapta kullanılan):

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

Bu yöntem daha hızlı olacak çünkü gerçek bir dizi kullanıyoruz ve bir dizi olduğunu varsaymıyoruz.

1000000Zamanlar için yukarıdaki yöntemlerin her birinin son satırını çağırmak şu kıyaslama sonuçlarına yol açar:

[İ] dizesini kullanma
0.24960017204285 Seconds

Str_split kullanma
0.18720006942749 Seconds

Bu, ikinci yöntemin çok daha hızlı olduğu anlamına gelir.


3

Hmm ... İşleri karmaşıklaştırmaya gerek yok. Temel bilgiler her zaman harika çalışıyor.

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

İleri yönde:

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

Çıktılar: abcdef

Ters yön:

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

Çıktılar: 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;
}

Bu cevabın yalnızca 1 olumlu oy almasına şaşırdım :( buradaki en / tek güvenilir cevap
Muhasebeci م

1

Cevapların çoğu İngilizce olmayan karakterler hakkında unutulmuş !!!

strlenkarakterleri değil, BYTES'i sayar, bu yüzden öyledir ve kardeş işlevleri İngilizce karakterlerle iyi çalışır, çünkü İngilizce karakterler hem UTF-8 hem de ASCII kodlamasında 1 baytta saklanır, çok baytlı dize işlevlerini kullanmanız gerekir mb_*

Bu, kodlanmış herhangi bir karakterle çalışacaktır .UTF-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);
}

Bu çıktılar

string(1) "a"
string(1) "b"
string(1) "c"
string(1) "d"
string(2) "أ"
string(2) "ب"
string(2) "ت"
string(2) "ث"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.