PHP - lặp trên các ký tự chuỗi


119

Có một cách hay để lặp lại trên các ký tự của một chuỗi không? Tôi muốn để có thể làm foreach, array_map, array_walk, array_filtervv trên các nhân vật của một chuỗi.

Kiểu truyền / tung hứng không đưa tôi đến bất cứ đâu (đặt toàn bộ chuỗi là một thành phần của mảng) và giải pháp tốt nhất tôi tìm thấy chỉ đơn giản là sử dụng vòng lặp for để xây dựng mảng. Nó cảm thấy như nên có một cái gì đó tốt hơn. Ý tôi là, nếu bạn có thể lập chỉ mục cho nó thì bạn cũng không thể lặp đi lặp lại chứ?

Đây là thứ tốt nhất tôi có

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ó phải không:

A) Một cách để tạo chuỗi lặp
B) Cách tốt hơn để xây dựng mảng ký tự từ chuỗi (và nếu vậy, làm thế nào về hướng khác?)

Tôi cảm thấy như tôi đang thiếu một cái gì đó rõ ràng ở đây.


Có lẽ bạn nên nói nhiều hơn về việc bạn đang cố gắng thực hiện ... có vẻ như có một cách tốt hơn để làm điều đó bằng cách sử dụng các hoạt động chuỗi bình thường.
Vinay Pai

1
không có một mục tiêu thực sự ở đây. chỉ là một sự tò mò mà tôi đã chơi với. Có vẻ kỳ lạ là mặc dù bạn có thể lập chỉ mục trên các chuỗi bạn không thể lặp lại. Tôi đã không biết cách sử dụng ví dụ có ý nghĩa, nhưng tôi vẫn muốn biết liệu có cách nào để lặp lại các chuỗi ký tự mà không xây dựng một mảng ký tự một cách
rõ ràng

Tuy nhiên, đó là điểm tốt, rõ ràng ví dụ của tôi khá nông cạn. tức là - hầu hết mọi thứ bạn làm theo array_filternghĩa này có thể được thực hiện tốt hơn với các hàm chuỗi hoặc reg-ex
jon_darkstar

Việc giải quyết projecteuler.net/pro Hiệu = 20 có thể là một ví dụ (mặc dù hơi khó hiểu).
Nick Edwards

một lưu ý, liên quan đến ($ i = 0; $ i <strlen ($ s); $ i ++) Tôi sẽ lưu trữ strlen ($ s) trong một biến trước khi lặp, theo cách này bạn sẽ không gọi strlen () nhiều hơn 1 lần
Amin

Câu trả lời:


176

Bước 1: chuyển đổi chuỗi thành một mảng bằng str_splithàm

$array = str_split($your_string);

Bước 2: lặp qua mảng vừa tạo

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

Bạn có thể kiểm tra các tài liệu PHP để biết thêm thông tin: str_split


hah wow vâng đó là nó. và tất nhiên implode có thể làm hướng khác. Tôi sẽ chấp nhận điều này sớm trừ khi ai đó có thể chỉ ra cách thực hiện phép lặp ngay trên sting
jon_darkstar

@jon_darkstar Tôi không biết ứng dụng của bạn, nhưng xin lưu ý rằng mỗi mục trong một mảng có một chi phí đáng kể (4byte IIRC). Bỏ qua điều đó, đó là cách 'khá' hơn: nikic.github.com/2011/12/12/NH
Daan Timmer

str_split() will split into bytes, rather than characters when dealing with a multi-byte encoded string.- Vì vậy, str_splitkhông thể làm việc với Unicode
Chúc mừng

84

Lặp lại chuỗi:

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

7
Đây có vẻ như là một câu trả lời tốt hơn bởi vì nó trả lời câu hỏi - tức là làm thế nào để lặp lại một chuỗi trái ngược với 'chuyển đổi thành mảng'.
Robin Andrew

2
CƯỜI LỚN!!!!! Mọi thứ @OmarTariq. Điều này là hiệu quả hơn nhiều so với câu trả lời được cung cấp.
0x476f72616e

5
Chỉ cần lưu ý rằng bạn đang gọi strlen()trên mỗi lần lặp. Không phải là một điều khủng khiếp, vì PHP có độ dài được tính toán trước, nhưng vẫn là một lời gọi hàm. Nếu bạn có nhu cầu về tốc độ, tốt hơn hãy lưu nó vào một biến trước khi bắt đầu vòng lặp.
Vilx-

2
Điều này không tốt cho các chuỗi đa chuỗi, bởi vì ở đây chúng tôi cài đặt bù byte, không phải là biểu tượng
alvery

2
@OmarTariq "Đây là câu trả lời. Có gì sai với thế giới?" .... Sai với thế giới là thế giới có các ngôn ngữ khác ngoài tiếng Anh, chức năng này như alvery đã nói sẽ lặp lại các byte trong chuỗi chứ không phải các ký tự.
Kế toán م

20

Nếu chuỗi của bạn bằng Unicode, bạn nên sử dụng preg_splitvới/u sửa đổi

Từ ý kiến ​​trong tài liệu 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
Đối với chuỗi đa bào, mb_splitđáng tin cậy hơn.
Élektra

12

Bạn cũng có thể chỉ truy cập $ s1 như một mảng, nếu bạn chỉ cần truy cập vào nó:

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

6

Được mở rộng từ câu trả lời @SeaBrightSystems, bạn có thể thử điều này:

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

Tôi không đồng ý, câu trả lời này không thêm giá trị, nó đưa ra một ví dụ hoạt động về cách str_split có thể hoạt động trong ứng dụng PHP. @SeaBrightSystems chỉ liên kết đến tài liệu, đôi khi không hữu ích khi một người đang cố gắng xem một chức năng có thể hoạt động như thế nào, đưa ra một ví dụ. Nếu không, hầu hết các câu trả lời SO sẽ chỉ là các liên kết đến php.net
Kurdtpage 16/8/2016

6

Đối với những người đang tìm kiếm cách nhanh nhất để lặp qua các chuỗi trong php, Ive đã chuẩn bị một bài kiểm tra điểm chuẩn.
Phương thức đầu tiên mà bạn truy cập trực tiếp các ký tự chuỗi bằng cách chỉ định vị trí của nó trong ngoặc và xử lý chuỗi như một mảng:

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

Bản thân tôi nghĩ rằng phương pháp sau là phương pháp nhanh nhất, nhưng tôi đã sai.
Như với phương pháp thứ hai (được sử dụng trong câu trả lời được chấp nhận):

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

Phương pháp này sẽ nhanh hơn vì chúng ta đang sử dụng một mảng thực sự và không cho rằng một mảng là một mảng.

Gọi dòng cuối cùng của từng phương pháp trên cho 1000000lần dẫn đến các kết quả điểm chuẩn này:

Sử dụng chuỗi [i]
0.24960017204285 Seconds

Sử dụng str_split
0.18720006942749 Seconds

Có nghĩa là phương pháp thứ hai là cách nhanh hơn.


3

Hmm ... Không cần phải phức tạp hóa mọi thứ. Những điều cơ bản làm việc tuyệt vời luôn.

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

Hướng về phía trước:

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

Đầu ra: abcdef

Hướng ngược lại:

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

Đầu ra: 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;
}

Tôi ngạc nhiên câu trả lời này chỉ có 1 upvote :( đây là câu trả lời đáng tin cậy nhất / duy nhất ở đây
Kế toán م

1

Hầu hết các câu trả lời quên về các ký tự không phải tiếng Anh !!!

strlenđếm BYTES, không phải ký tự, đó là lý do tại sao nó và các hàm anh chị em hoạt động tốt với các ký tự tiếng Anh, bởi vì các ký tự tiếng Anh được lưu trữ trong 1 byte trong cả mã hóa UTF-8 và ASCII, bạn cần sử dụng các hàm chuỗi đa chuỗi mb_*

Điều này sẽ làm việc với bất kỳ ký tự được mã hóa trongUTF-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);
}

Đầu ra này

string(1) "a"
string(1) "b"
string(1) "c"
string(1) "d"
string(2) "أ"
string(2) "ب"
string(2) "ت"
string(2) "ث"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.