2024 日本 PHP 研討會

preg_split

(PHP 4, PHP 5, PHP 7, PHP 8)

preg_split使用正規表達式分割字串

說明

preg_split(
    字串 $pattern,
    字串 $subject,
    整數 $limit = -1,
    整數 $flags = 0
): 陣列|false

使用正規表達式分割給定的字串。

參數

pattern (模式)

要搜尋的模式,以字串表示。

subject (主體)

輸入字串。

limit (限制)

如果指定了 limit 參數,則只會返回最多 limit 個子字串,其餘字串會被放在最後一個子字串中。 limit 值為 -1 或 0 表示「無限制」。

flags 標記

flags 標記可以是以下標記的任意組合(使用 | 位元運算子組合)

PREG_SPLIT_NO_EMPTY
如果設定此標記,preg_split() 只會返回非空的片段。
PREG_SPLIT_DELIM_CAPTURE
如果設定此標記,分隔符號模式中的括號表達式也會被擷取並返回。
PREG_SPLIT_OFFSET_CAPTURE

如果設定此標記,對於每個出現的匹配項,也會返回附加的字串偏移量。請注意,這會改變返回值的結構,變成一個陣列,其中每個元素都是一個陣列,包含匹配的字串(位於索引 0)及其在 subject 中的字串偏移量(位於索引 1)。

返回值

返回一個陣列,包含 subject 字串依 pattern 匹配的邊界分割的子字串;失敗時返回 false

錯誤/例外

如果傳遞的正規表達式模式無法編譯成有效的正規表達式,則會發出 E_WARNING 警告。

範例

範例 #1 preg_split() 範例:取得搜尋字串的各個部分

<?php
// 使用任意數量的逗號或空白字元分割字串,
// 空白字元包含 " ", \r, \t, \n 和 \f
$keywords = preg_split("/[\s,]+/", "hypertext language, programming");
print_r($keywords);
?>

上述範例將輸出

Array
(
    [0] => hypertext
    [1] => language
    [2] => programming
)

範例 #2 將字串分割成個別字元

<?php
$str
= 'string';
$chars = preg_split('//', $str, -1, PREG_SPLIT_NO_EMPTY);
print_r($chars);
?>

上述範例將輸出

Array
(
    [0] => s
    [1] => t
    [2] => r
    [3] => i
    [4] => n
    [5] => g
)

範例 #3 將字串分割成匹配項及其偏移量

<?php
$str
= 'hypertext language programming';
$chars = preg_split('/ /', $str, -1, PREG_SPLIT_OFFSET_CAPTURE);
print_r($chars);
?>

上述範例將輸出

Array
(
    [0] => Array
        (
            [0] => hypertext
            [1] => 0
        )

    [1] => Array
        (
            [0] => language
            [1] => 10
        )

    [2] => Array
        (
            [0] => programming
            [1] => 19
        )

)

注意事項

提示

如果您不需要正規表達式的強大功能,您可以選擇速度更快(雖然更簡單)的替代方案,例如 explode()str_split()

提示

如果比對失敗,將會返回一個只包含輸入字串的單元素陣列。

參見

新增註解

使用者貢獻的註解 18 則註解

jan dot sochor at icebolt dot info
15 年前
有時 PREG_SPLIT_DELIM_CAPTURE 會產生奇怪的結果。

<?php
$content
= '<strong>Lorem ipsum dolor</strong> sit <img src="test.png" />amet <span class="test" style="color:red">consec<i>tet</i>uer</span>.';
$chars = preg_split('/<[^>]*[^\/]>/i', $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
print_r($chars);
?>
產生
陣列
(
[0] => Lorem ipsum dolor
[1] => sit <img src="test.png" />amet
[2] => consec
[3] => tet
[4] => uer
)

因此分隔符號模式遺失了。如果您想要取得這些模式,請記得使用括號。

<?php
$chars
= preg_split('/(<[^>]*[^\/]>)/i', $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
print_r($chars); //已新增括號
?>
產生
陣列
(
[0] => <strong>
[1] => Lorem ipsum dolor
[2] => </strong>
[3] => sit <img src="test.png" />amet
[4] => <span class="test" style="color:red">
[5] => consec
[6] => <i>
[7] => tet
[8] => </i>
[9] => uer
[10] => </span>
[11] => .
)
buzoganylaszlo at yahoo dot com
15 年前
擴展 m.timmermans 的解決方案,您可以使用以下程式碼作為搜尋表達式剖析器

<?php
$search_expression
= "apple bear \"Tom Cruise\" or 'Mickey Mouse' another word";
$words = preg_split("/[\s,]*\\\"([^\\\"]+)\\\"[\s,]*|" . "[\s,]*'([^']+)'[\s,]*|" . "[\s,]+/", $search_expression, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
print_r($words);
?>

結果如下:
陣列
(
[0] => apple
[1] => bear
[2] => Tom Cruise
[3] => or
[4] => Mickey Mouse
[5] => another
[6] => word
)

1. 可接受的分隔符號:空白字元(空格、Tab、換行等)以及逗號。

2. 您可以使用單引號(') 或雙引號(") 來包含多個單字的表達式。
canadian dot in dot exile at gmail dot com
9 年前
這個正規表達式會將一個長字串依據單字邊界拆分成一個子字串陣列,每個子字串都有最大長度限制。

我使用 `preg_match_all()` 搭配這個正規表達式;但是,我將這個例子發佈在這裡(`preg_split()` 的頁面上),因為這是我當初想找到解決方案時搜尋的地方。

希望它能幫其他人省點時間。

<?php
// 長字串範例
$long_string = '您的 IP 位址將與提交的註釋一起記錄,並在 PHP 手冊使用者註釋郵件列表中公開。IP 位址作為註釋審核流程的一部分記錄,並不會顯示在 PHP 手冊本身中。';

// 例如,在 60 個字元或更少的位置進行「斷行」
$max_len = 60;

// 此正規表示式將在 1 個或多個非單字字元(空格或標點符號)的任何子字串上分割 $long_string
if(preg_match_all("/.{1,{$max_len}}(?=\W+)/", $long_string, $lines) !== False) {

// $lines 現在包含一個子字串陣列,每個子字串大約會有
// $max_len 個字元 - 取決於最後一個單字結束的位置以及
// 在最後一個單字之後找到的「非單字」字元的數量
for ($i=0; $i < count($lines[0]); $i++) {
echo
"[$i] {$lines[0][$i]}\n";
}
}
?>
Hayley Watson
5 年前
假設您使用的是 UTF-8,則可以使用此函數將 Unicode 文字分割成個別的程式碼點,而無需使用多位元組擴充功能。

<?php

preg_split
('//u', $text, -1, PREG_SPLIT_NO_EMPTY);

?>

「English」、「Español」和「Русский」這幾個字的長度都是七個字母。但 strlen 會分別回報字串長度為 7、8 和 14。上面的 preg_split 在所有三種情況下都會返回一個七元素陣列。

它會將 '한국어' 分割成陣列 ['한', '국', '어'],而不是 str_split($text) 會產生的 9 個字元的陣列。
eric at clarinova dot com
13 年前
這是另一種分割駝峰式大小寫 (CamelCase) 字串的方法,它比使用前瞻和後顧斷言的表示式更簡單

preg_split('/([[:upper:]][[:lower:]]+)/', $last, null, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY)

它將整個駝峰式大小寫的單字作為分隔符號,然後返回分隔符號 (PREG_SPLIT_DELIM_CAPTURE) 並省略分隔符號之間的空值 (PREG_SPLIT_NO_EMPTY)
Daniel Schroeder
14 年前
如果您想用一個字元分割,但想忽略該字元在跳脫的情況,請使用後顧斷言。

在此範例中,字串將以 ":" 分割,但 "\:" 將被忽略

<?php
$string
='a:b:c\:d';
$array=preg_split('#(?<!\\\)\:#',$string);
print_r($array);
?>

結果如下:

陣列
(
[0] => a
[1] => b
[2] => c\:d
)
dewi at dewimorgan dot com
3 年前
請注意,假設 PREG_SPLIT_NO_EMPTY 不會返回空值,或者如果您使用 PREG_SPLIT_DELIM_CAPTURE 不會看到分隔符號是不安全的,因為在某些邊緣情況下,這些假設並不成立。

<?php
# 正如預期,用自身分割字串會返回兩個空字串:
var_export(preg_split("/x/", "x"));

array (
0 => '',
1 => '',
)

# 但如果我們加上 PREG_SPLIT_NO_EMPTY,則我們會得到分隔符號,而不是空陣列。
var_export(preg_split("/x/", "x", PREG_SPLIT_NO_EMPTY));

array (
0 => 'x',
)

如果我們嘗試分割一個空字串,即使使用 PREG_SPLIT_NO_EMPTY,我們也會得到一個空字串,而不是一個空陣列。
var_export(preg_split("/x/", "", PREG_SPLIT_NO_EMPTY));

array (
0 => '',
)
?>
PhoneixSegovia at gmail dot com
14 年前
使用反向斷言匹配變數時必須小心。
例如
'/(?<!\\\)\r?\n)/'
要匹配前面沒有 \ 的新行,並不如預期般運作,因為它會將 \r 匹配為反向斷言(因為它不是 \),並且在 \n 之前是可選的。

例如,您必須使用這個
'/((?<!\\\|\r)\n)|((?<!\\\)\r\n)/'
這會匹配一個單獨的 \n(前面沒有 \r 或 \)或一個前面沒有 \ 的 \r\n。
Steve
19 年前
如果字串以分隔符號結尾,preg_split() 的行為與 perl 的 split() 不同。這段 perl 程式碼將會印出 5

my @a = split(/ /, "a b c d e ");
print scalar @a;

相對應的 php 程式碼會印出 6

<?php print count(preg_split("/ /", "a b c d e ")); ?>

這不一定是一個錯誤(文件中沒有任何地方說明 preg_split() 的行為與 perl 的 split() 相同),但它可能會讓 perl 程序員感到驚訝。
php at dmi dot me dot uk
15 年前
使用具有前瞻和後顧斷言的 preg_split() 來分割駝峰式大小寫的字符串

<?php
function splitCamelCase($str) {
return
preg_split('/(?<=\\w)(?=[A-Z])/', $str);
}
?>
jetsoft at iinet.net.au
20 年前
為了闡明「limit」參數和 PREG_SPLIT_DELIM_CAPTURE 選項的用法:

<?php
$preg_split
('(/ /)', '1 2 3 4 5 6 7 8', 4 ,PREG_SPLIT_DELIM_CAPTURE );
?>

會返回

('1', ' ', '2', ' ' , '3', ' ', '4 5 6 7 8')

因此,實際上您會得到 7 個數組項,而不是 4 個
csaba at alum dot mit dot edu
15 年前
如果任務對於 preg_split 來說太複雜,preg_match_all 可能會派上用場,因為 preg_split 本質上是一個特例。

我想用特定字符(星號)分割字符串,但前提是它沒有被轉義(前面沒有反斜線)。 因此,我應該確保在任何用作分隔符的星號之前有偶數個反斜線。 正則表達式中的後顧斷言不起作用,因為前面反斜線序列的長度無法固定。 所以我改用 preg_match_all

<?php
// 用未轉義的星號分割字符串
// 反斜線是轉義字符
$splitter = "/\\*((?:[^\\\\*]|\\\\.)*)/";
preg_match_all($splitter, "*$string", $aPieces, PREG_PATTERN_ORDER);
$aPieces = $aPieces[1];

// $aPieces 現在包含已分割的字符串
// 可以安全地對每個部分進行反轉義
foreach ($aPieces as $idx=>$piece)
$aPieces[$idx] = preg_replace("/\\\\(.)/s", "$1", $piece);
?>
david dot binovec at gmail dot com
13 年前
Limit = 1 的行為可能會造成混淆。重點是,如果 limit 等於 1,則只會產生一個子字符串。 因此,唯一的子字符串將是第一個子字符串,同時也是最後一個子字符串。 字符串的其餘部分(第一個分隔符之後)將被放置到最後一個子字符串中。 但最後一個也就是第一個,也是唯一一個。

<?php

$output
= $preg_split('(/ /)', '1 2 3 4 5 6 7 8', 1);

echo
$output[0] //會回傳整個字串!;

$output = $preg_split('(/ /)', '1 2 3 4 5 6 7 8', 2);

echo
$output[0] //會回傳 1;
echo $output[1] //會回傳 '2 3 4 5 6 7 8';

?>
Miller
10 年前
這是一個用於截斷文字字串同時保留空白字元(例如,從文章中擷取摘要並保留換行符號)的函式。當然,它不適用於 HTML。

<?php
/**
* 依照字數截斷文字字串
* @param string $text 要截斷的文字
* @param int $max_words 最大字數
* @return string 截斷後的文字
*/
function limit_words ($text, $max_words) {
$split = preg_split('/(\s+)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$truncated = '';
for (
$i = 0; $i < min(count($split), $max_words*2); $i += 2) {
$truncated .= $split[$i].$split[$i+1];
}
return
trim($truncated);
}
?>
Walf
2 年前
使用 PREG_SPLIT_DELIM_CAPTURE 而不使用 PREG_SPLIT_NO_EMPTY 可以確保結果中所有奇數索引的鍵都包含分隔符號。這讓後續處理更具可預測性,而且空字串始終可以在最後被過濾掉。
kenorb at gmail dot com
15 年前
如果您需要轉換沒有預設值的函式參數和參考,您可以嘗試這段程式碼

<?php
$func_args
= '$node, $op, $a3 = NULL, $form = array(), $a4 = NULL'
$call_arg = preg_match_all('@(?<func_arg>\$[^,= ]+)@i', $func_args, $matches);
$call_arg = implode(',', $matches['func_arg']);
?>
結果:字串 = "$node,$op,$a3,$form,$a4"
markac
9 年前
將字串分割成單字。

<?php
$string
= 'This - is a, very dirty "string" :-)';

// 分割成單字
$wordlist = preg_split('/\W/', $string, 0, PREG_SPLIT_NO_EMPTY);

// 只回傳至少 2 個字元的單字
$wordlist = array_filter($wordlist, function($val) {
return
strlen($val) >= 2;
});

// 顯示
var_dump($wordlist);
?>

結果

陣列 (大小=5)
0 => 字串 'This' (長度=4)
1 => 字串 'is' (長度=2)
3 => 字串 'very' (長度=4)
4 => 字串 'dirty' (長度=5)
5 => 字串 'string' (長度=6)
php at haravikk dot me
8 年前
當使用 PREG_SPLIT_OFFSET_CAPTURE 選項時,所有結果都會放在單一陣列中,這通常是不理想的,因為這表示您必須過濾掉任何您想要檢查但不想保留的界定符號。

為了避免這個問題,您可以改用 preg_match_all() 執行分割。為了比較,這裡有兩個範例,都以冒號和分號字元進行分割

<?php $pieces_with_delimiters = preg_split('/[;:]/', $input, -1, PREG_SPLIT_OFFSET_CAPTURE); ?>

<?php preg_match_all('/([^;:]*)([;:]|$)/', $input, $matches);
list(,
$pieces, $delimiters) = $matches ?>

後者需要更複雜的模式,但會產生更方便使用的結果集,取決於您想要如何使用它們。
To Top