PHP Conference Japan 2024

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 为 -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 条注释

43
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] => 用户
[10] => </span>
[11] => .
)
20
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. 可接受的分隔符:空格(空格、制表符、换行符等)和逗号。

2. 您可以对包含多个单词的表达式使用单引号 (') 或双引号 (")。
11
canadian dot in dot exile at gmail dot com
9年前
此正则表达式会将长字符串单词分割成子字符串数组,每个子字符串具有最大长度,但仅在单词边界处分割。

我将正则表达式与 preg_match_all() 一起使用;但是,我在这里(在 preg_split() 的页面上)发布此示例,因为当我想要找到一种执行此操作的方法时,我就是在这里查找的。

希望它能为某些人节省一些时间。

<?php
// 长字符串单词示例
$long_string = 'Your IP Address will be logged with the submitted note and made public on the PHP manual user notes mailing list. The IP address is logged as part of the notes moderation process, and won\'t be shown within the PHP manual itself.';

// 例如,在 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";
}
}
?>
7
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 字符数组。
13
eric at clarinova dot com
13年前
这是另一种分割 CamelCase 字符串的方法,它比使用前瞻和后顾的表达式更简单

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

它使整个 CamelCased 单词成为分隔符,然后返回分隔符(PREG_SPLIT_DELIM_CAPTURE)并省略分隔符之间的空值(PREG_SPLIT_NO_EMPTY)
13
Daniel Schroeder
14年前
如果要按字符分割,但要在字符被转义的情况下忽略该字符,请使用后顾断言。

在此示例中,字符串将按“:”分割,但“\:”将被忽略

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

结果为

数组
(
[0] => a
[1] => b
[2] => c\:d
)
1
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 => '',
)
?>
6
PhoneixSegovia at gmail dot com
14年前
使用后顾断言匹配变量时,必须谨慎。
例如
'/(?<!\\\)\r?\n)/'
在它前面没有 \ 时匹配换行符不会按预期进行,因为它会将 \r 作为后顾断言(因为它不是 \),并且在 \n 之前是可选的。

例如,您必须使用此方法
'/((?<!\\\|\r)\n)|((?<!\\\)\r\n)/'
这将匹配单独的 \n(前面没有 \r 或 \)或前面没有 \ 的 \r\n。
4
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 程序员感到意外。
4
php at dmi dot me dot uk
15年前
使用带有前瞻和后顾的 preg_split() 分割驼峰式字符串

<?php
function splitCamelCase($str) {
return
preg_split('/(?<=\\w)(?=[A-Z])/', $str);
}
?>
7
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 个。
3
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);
?>
3
[email protected]
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';

?>
1
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);
}
?>
0
Walf
2年前
在不使用 PREG_SPLIT_NO_EMPTY 的情况下使用 PREG_SPLIT_DELIM_CAPTURE 保证结果中所有奇数键都将包含分隔符。这使得进一步处理更可预测,并且总可以在最后过滤掉空字符串。
0
[email protected]
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"
-3
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)
-3
[email protected]
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