按换行符拆分字符串

286
我有一个带有换行符的字符串,我想将该字符串转换为一个数组,并且对于每个新行,在数组中跳过一个索引位置。
如果字符串为:
My text1
My text2
My text3

我想要的结果是这样的:

Array
(
    [0] => My text1
    [1] => My text2
    [2] => My text3
)

19个回答

449

我一直非常成功地使用了这个:

$array = preg_split("/\r\n|\n|\r/", $string);

(已更新为包含最终\r,感谢@LobsterMan)


1
这就是答案。验证过的那个是错误的。好吧,Hesselbom 也有它...你也可以使用这个等价式:preg_split('/\n|\r/', $string, -1, PREG_SPLIT_NO_EMPTY); 为了美观起见 :) 为什么这是唯一正确的答案?因为你不能假设你会得到哪种类型的行尾符:Mac (\r)、Windows (\r\n) 或 Unix (\n)。 - Ninj
17
\R 匹配 \n\r\r\n - mpen
2
或者更短的 /\r?\n/ - Jason Schilling
1
这个例子是正确的,因为你不能仅仅基于单个字符进行任何分割操作。如果你这样做,在 '\r' 或者 '\n' 上触发,你最终会得到一个多余的空行,特别是在 Windows "\r\n" 结尾的情况下。而且重要的是先测试两个字符的 Windows 分隔符。 - AndresRohrAtlasInformatik
什么是 <br />? - Datadimension

336
你可以使用explode函数,以"\n"作为分隔符:
$your_array = explode("\n", $your_string_from_db);

例如,如果您有以下代码:

$str = "My text1\nMy text2\nMy text3";
$arr = explode("\n", $str);
var_dump($arr);

你将得到以下输出:

array
  0 => string 'My text1' (length=8)
  1 => string 'My text2' (length=8)
  2 => string 'My text3' (length=8)
注意,您必须使用双引号字符串,因此\n实际上被解释为换行符。 (请参阅该手册页面了解更多详细信息。)

61
可以使用预定义常量 PHP_EOL 替代 \n - Tim
47
请大家注意,这个解决方案并不适用于所有情况,请小心使用。我发现David的回答最为有效。 - Maurice
2
你必须在 \n 或 \r 处进行分割,以便处理所有类型的文本 - 这仅适用于 Linux 和 Windows 的换行符。Mac 的换行符将被忽略!(\r) - Steve Horvath
1
我猜Tim的回答/评论不正确,因为这只会匹配YOUR系统中的换行符,但当您获得来自其他系统具有换行符的字符串时,它将无法工作!在电子邮件中遇到了这个问题。 - Asara
10
不,这个答案和对该答案的评论是错误的!因为它没有考虑操作系统的换行符,尤其是 PHP_EOL。你必须使用 preg_split("/\\r\\n|\\r|\\n/", $value) - kjdion84
显示剩余3条评论

293

不同平台上,换行符的定义不同,有\r\n、\r或\n。

使用RegExp来拆分字符串,你可以用\R匹配所有三个换行符。

所以对于你的问题:

$array = preg_split ('/$\R?^/m', $string);

这将匹配Windows、Mac和Linux上的换行符!


3
我也使用了这个方法,而不是这个帖子中被接受的答案或其他任何答案。我留下这个评论作为信息提供。 - Seth Malaki
3
实际上,这对我没有起作用。有时候换行符仍然存在于数组键中。 - Maurice
37
请使用 $array = preg_split ('/\R/', $string); 进行分割。 - Jan Goyvaerts
19
有时不起作用!preg_split("/\r\n|\n|\r/", $string) 是更好的选择。 - Alexey B.
2
我同意'Maurice'所说的,对我没有用。不过,'Jan'提供的解决方案有效... - pedromanoel
显示剩余6条评论

40

PHP已经知道当前系统的换行符。只需使用EOL常量。

explode(PHP_EOL,$string)

21
可以在Windows上编辑文件,或者像这个例子中一样,在Windows上编辑数据库条目,然后在Linux系统上使用它。我认为采用一种普遍的方法会更好。 - Cranio
2
我不确定这是否正确。如果网页上的文本区域被提交,它可能具有不同的行尾字符,这取决于用户的浏览器,而不是服务器的操作系统。因此,无论您使用什么操作系统,都需要能够解析任何内容。当然,这是假设您正在进行网络开发。 - Magmatic
1
你可能需要在结果字符串上使用 trim() 函数来删除任何多余的空格。 - Tim

39
一个比David的答案更快(快得多)的替代方法是使用str_replaceexplode
$arrayOfLines = explode("\n",
                    str_replace("\r\n","\n",$str)
            );

发生的情况是:
由于换行符可能以不同的形式出现,我使用str_replace将\r\n、\n\r和\r替换为\n(同时保留原始的\n)。
然后在\n上进行分割,你就得到了一个包含所有行的数组。

我对这个页面的源代码进行了1000次循环的行分割的基准测试:
preg_replace的平均时间为11秒
str_replace & explode的平均时间约为1秒

有关我的论坛的更多详细信息和基准测试信息


您的论坛链接(以及整个域名)似乎已经无法访问。 - Nikita 웃
哪个操作系统会反向使用换行序列\n\r - mickmackusa
@mickmackusa,我不知道有没有。那是很久以前的事了,我不确定为什么我会这样做。我在想是否应该删除\n\r - Reed
2
据我所知,您只需要在搜索数组中保留\r\n(而且它不再需要是一个数组)。我对“preg_”比其他方法慢11倍的说法很感兴趣。您没有包含您使用的模式。您上面的代码片段对输入进行了4次遍历。一个好的“preg_”技巧只需要对输入进行一次遍历。正则表达式并不以其速度著称,但我认为您的说法需要证实。如果您要保留这个性能声明,请发布您的基准测试详细信息。 - mickmackusa

22

David的方向很好,但它错过了 \r。以下方法适用于我:

$array = preg_split("/(\r\n|\n|\r)/", $string);

捕获组并不是必需的。 - mickmackusa

17

想要成功地将字符串按换行符分割成数组,不需要使用 preg_* 函数,preg 模式,str_replace 等。在所有情况下,无论是 Linux、Mac 还是 Windows,以下代码都可以实现。

<?php
    $array = explode(PHP_EOL, $string);
    // ...
    $string = implode(PHP_EOL, $array);
?>

PHP_EOL是一个常量,保存着服务器平台使用的换行符。


7
文件可能来自另一个系统,具有不同的换行符,特别是在使用PHP的网络环境中。 - Luca C.
这正是该常量存在的原因...并处理了特定的问题。 - Spooky
如果你从Windows中取出一个文件,它和从Unix或Mac中取出的同名文件是不一样的,对吧? - Luca C.
如果您始终在所有地方使用纯utf-8,包括utf8文件,并且您的代码中除了PHP_EOL用于换行检测之外没有其他内容,那么它将如描述的那样匹配,不会发生任何意外行为。请记住,不仅仅是我在大声喊叫和声称这一点。 PHP_EOL的可用性已经得到了确认。 - Spooky
在我的情况下,也就是我读到这个问题的情况下,可能并不总是有效。我从其他网站下载文件并将它们按行分割,它们可能是UTF8或者不是,它们可能来自Windows或Unix换行符,因此我使用了一个正则表达式来匹配任何换行符变体。 - Luca C.
1
在您的情况下,如果来源来自其他地方并且格式不正确,那么最好使用str_replace(比regexp更快)。总之,无论是regexp还是str_replace或PHP_EOL,都有一句老话说:“如果它能工作-不要碰它!”。 :) - Spooky

15

使用方法: $array = preg_split('/\s*\R\s*/', trim($text), NULL, PREG_SPLIT_NO_EMPTY);

这对我来说是最好的选择,因为它自动消除了前导(第二个 \s*)和尾随(第一个 \s*)空格,并跳过空行(PREG_SPLIT_NO_EMPTY 标志)。

选项

如果您想保留前导空格,只需去掉第二个 \s* 并将其变为 rtrim() 即可...

$array = preg_split('/\s*\R/', rtrim($text), NULL, PREG_SPLIT_NO_EMPTY);

如果您需要保留空行,请删除NULL(它只是一个占位符)和PREG_SPLIT_NO_EMPTY标志,如下所示...
$array = preg_split('/\s*\R\s*/', trim($text));

或者保留前导空白和空行...

$array = preg_split('/\s*\R/', rtrim($text));

我认为没有什么理由需要保留行末的空格,所以建议保留第一个\s*。但是,如果你只想按换行符分割(如标题所示),那么它就非常简单(如Jan Goyvaerts提到的)...

$array = preg_split('/\R/', $text);

11

这个页面上有直接和间接回答的混合,并且一些评论中有很好的建议,但没有一个答案能代表我在自己的项目中所写的内容。

PHP转义序列\R文档: https://www.php.net/manual/en/regexp.reference.escape.php#:~:text=line%20break,\r\n

代码: (演示)

$string = '
My text1

My text2


My text3


';

var_export(
    preg_split('/\R+/', $string, 0, PREG_SPLIT_NO_EMPTY)
);

输出:

array (
  0 => 'My text1',
  1 => 'My text2',
  2 => 'My text3',
)

OP未提及从行中删除水平空格字符,因此没有期望在变量(系统无关)换行符上分离\s\h.

虽然PHP_EOL是合理的建议,但它缺乏适当地扩展字符串的灵活性,特别是在换行符序列来自其他操作系统时。

使用非正则表达式分隔通常会更加间接,因为它需要字符串准备工作。此外,如果有不想要的空白行需要清除,则需要进行调整。

使用\R+(一个或多个连续的换行符序列)和PREG_SPLIT_NO_EMPTY函数标志将在单个简洁的函数调用中提供无间隙的索引数组。一些人对正则表达式有偏见,但这是为什么应该使用正则表达式的完美案例。如果出于有效原因(例如,您正在处理数十万个数据点),性能是一个问题,请继续投资于基准测试和微优化。除此之外,只需使用这一行代码,以使您的代码简洁、强大且直接。


9
explode("\n", $str);

“(而不是')”非常重要,否则换行符将无法解释。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接