通过换行符拆分 PHP 字符串

331

很简单,对吧?不过,这行代码似乎有问题 :-\

$skuList = explode('\n\r', $_POST['skuList']);

32
单引号表示“不解析该字符串”。@Select0r的回答可能是你在寻找的。 - Ryan Kinal
4
可能是重复问题:如何从PHP字符串中删除换行符和回车符? 这个问题已经是可靠地从字符串中删除换行符和其他一些问题的重复内容。 - Gordon
10
除了其他人提到的单引号之外,CRLF配对应该是\r\n而不是相反的。 - Powerlord
2
请记住以下内容:\R etur \N - l00k
$skuList = explode("\n\r", $_POST['skuList']); 应该可以工作。这真的取决于您的字符串变量是如何包装的。可能是 " " 或 ' '。对于 $string = 'abc\n\rdef',请使用 $skuList = explode('\n\r', $string); - nh-labs
19个回答

554

最佳实践

如第一个答案中的评论所述,最佳实践是使用 PHP 常量PHP_EOL,该常量表示当前系统的行尾(End Of Line)。

$skuList = explode(PHP_EOL, $_POST['skuList']);

PHP提供了许多其他非常有用的常量,您可以使用它们使您的代码与系统无关,请参见此链接以查找有用且与系统无关的目录常量。

警告

这些常量使您的页面与系统无关,但是当您将使用这些常量与存储在另一个系统上的数据移动到另一个系统时,您可能会遇到问题。新系统的常量可能与先前系统的常量不同,并且存储的数据可能不再起作用。因此,在将数据存储到文件之前,请完全解析数据以删除任何系统相关部分。

更新

Andreas的评论使我意识到,我在此处提供的“最佳实践”解决方案并不适用于所描述的用例:服务器的EOL(PHP)与浏览器(任何操作系统)正在使用的EOL没有任何关系,但(浏览器)是字符串来自的地方。

因此,请使用 @Alin_Purcaru 的解决方案来覆盖您的所有基础:

$skuList = preg_split('/\r\n|\r|\n/', $_POST['skuList']);

24
您不能使用PHP_EOL,因为系统和输入源之间没有任何关系。如果用户在Windows中输入新行,而PHP在Linux上运行,则结果可能会出现错误。 - barell
1
@barell 没错,这就是我在“警告”部分描述的情况 ;) 问题并没有明确说明它是存储在数据库中的旧输入。请阅读“警告”部分,您会发现我已经涵盖了那种情况。 - Larzan
8
对于这种情况,这个答案是错误的。不要在此情况下使用PHP_EOL常量作为输入源(例如用户的浏览器)绝对不是您的系统。使用能够处理所有不同行尾的解决方案(来自Alin Purcaru的答案)。 - Andreas
所以,如果我切换服务器并且EOL PHP设置更改,那么每当我使用此命令从我的数据库中提取文本时就会出现问题? - Adam
@Adam 是的,你应该对存储在数据库中的字符串进行规范化处理,并始终以某种方式存储它们,而不是使用系统的EOL。这样,当你更换系统时,你不会遇到问题,因为所有在数据库中的字符串都有相同的EOL字符串。 - Larzan

306

覆盖所有情况,不要依赖于输入来自Windows环境。

$skuList = preg_split("/\\r\\n|\\r|\\n/", $_POST['skuList']);
或者
$skuList = preg_split('/\r\n|\r|\n/', $_POST['skuList']);

28
如果行尾符为\r\n,则会导致数组元素为空。为了避免这种情况,可以使用以下方法之一: preg_split('/\n|\r/', $_POST['skuList'], -1, PREG_SPLIT_NO_EMPTY);(注意,使用该标志时\r\n变得不必要),或者在\r之前 插入 \r\npreg_split('/\r\n|\n|\r/', $_POST['skuList']); - webbiedave
3
PREG_SPLIT_NO_EMPTY很好,但它会删除空行。这可能是想要的,也可能不是。 - jms
1
这个模式可以匹配每一个字母,因为即使没有任何内容也会成功匹配。 "?"表示0或1次,因此即使 \r 和 \n 都不存在也有可能匹配成功。 你说“固定的”,但我没有看到。 我使用了 /(\r|\n)+/。 - Rolf
1
@Rolf 看来我匆忙修改了一下。现在已经纠正过来了。你应该使用什么取决于你是否想在输出中包含空行。我的答案中的选项也会返回空行。 - Alin Purcaru
3
@AlinPurcaru能否在回答中澄清哪个(两个、任意一个或都不是)会返回空白,哪个不会? - Patrick
显示剩余5条评论

160

尝试使用"\n\r"(双引号)或只使用"\n"

如果您不确定具有哪种类型的EOL,请在分割字符串之前运行str_replace,将"\n\r"替换为"\n"


57
在PHP中,单引号表示“不解析此字符串”。这意味着您的控制字符不会被解析,而是按原样(不是换行和回车符,而是实际的 '\n\r' 文本)使用。使用双引号则表示“解析此字符串”,因此您的控制字符将被解析。+1 - Ryan Kinal
18
/n/r? I know the OP wrote that but the correct windows eol is \r\n - webbiedave
21
考虑PHP中的换行符常量:PHP_EOL - Daniel W.
大家好,这绝对是正确的答案!我想知道为什么 @Alin Purcaru 的答案获得了44票.. 它是错的!虽然它似乎做了这个工作,但它并不总是正确的.. 所以这是我的评论,为了帮助任何陷入同样困境的人。 - Rafik Bari
4
请忽略\r,最后一个使用它而不使用\n的操作系统是OS9(http://en.wikipedia.org/wiki/Newline#Representations)。因此,这将为您提供最佳结果:`explode("\n", str_replace("\r", '', $string));`。 - DanielM

18
无论您的系统使用什么作为换行符,如果内容可能是在系统外生成的,这都无关紧要。
在收到所有这些答案之后,我感到惊讶的是,没有人简单地建议使用`\R`转义序列。在我自己的项目中,只有一种方式我会考虑实现这个。`\R`提供了最简洁和直接的方法。

https://www.php.net/manual/en/regexp.reference.escape.php#:~:text=line%20break:%20matches%20\n,%20\r%20and%20\r\n

代码:(演示)
$text = "one\ntwo\r\nthree\rfour\r\n\nfive";

var_export(preg_split('~\R~', $text));

输出:

array (
  0 => 'one',
  1 => 'two',
  2 => 'three',
  3 => 'four',
  4 => '',
  5 => 'five',
)

如果您不希望在输出中出现空元素,那么请使用:演示
  • 使用正则表达式引擎根据一个或多个换行序列进行拆分

    var_export(preg_split('~\R+~', $text));  // 可能会在数组的开头和/或结尾生成空元素
    
  • 删除长度为零的元素

    var_export(preg_split('~\R~', $text, -1, PREG_SPLIT_NO_EMPTY));
    
  • [最佳] 使用正则表达式引擎根据一个或多个换行序列进行拆分,并删除长度为零的元素

    var_export(preg_split('~\R+~', $text, -1, PREG_SPLIT_NO_EMPTY)); 
    

15

尝试

explode(chr(10), $_POST['skuList']);

15

这里有很多内容:

  • 你需要使用双引号而不是单引号,否则转义字符将无法被转义。
  • 正常顺序是\r\n,而不是 \n\r
  • 根据源代码的不同,你可能只会得到\n,没有\r(甚至在非典型情况下,可能只有\r)。

鉴于最后一点,您可能会发现使用所有可能的变量的preg_split()会比使用explode()更可靠地拆分数据。但是您也可以仅使用\n来使用explode(),然后使用trim()删除任何悬挂的\r字符。


14

这个 PHP 函数通过换行符将字符串分割为数组

注意: Windows 中的换行符是 \r\n,而在 LinuxUnix 中是 \n
该函数会将所有换行符更改为Linux模式,然后进行分割。
请注意,空行将被忽略。

function splitNewLine($text) {
    $code=preg_replace('/\n$/','',preg_replace('/^\n/','',preg_replace('/[\r\n]+/',"\n",$text)));
    return explode("\n",$code);
}

例子

$a="\r\n\r\n\n\n\r\rsalam\r\nman khobam\rto chi\n\rche khabar\n\r\n\n\r\r\n\nbashe baba raftam\r\n\r\n\r\n\r\n";
print_r( splitNewLine($a) );

输出

Array
(
    [0] => salam
    [1] => man khobam
    [2] => to chi
    [3] => che khabar
    [4] => bashe baba raftam
)

1
我绝对不会使用你的代码片段。对于你发明的字符串,最直接/合理的技术应该是 var_export(preg_split('~\R+~', $a, 0, PREG_SPLIT_NO_EMPTY));。其他任何方法都不是聪明的做法。演示 - mickmackusa

9
为保留换行符(作为空白项在数组中):
$skuList = preg_split('/\r\n|\n\r|\r|\n/', $_POST['skuList']);`

这个方法可以处理不常见的 \n\r 以及常见的 \n\r, \n 和 \r。请注意,@Alin_Purcaru 的解决方案非常相似,但无法处理 \n\r。

要移除换行符(数组中没有空白项):

$skuList = preg_split('/[\r\n]+/', $_POST['skuList']);

PHP测试
这些表达式已在以下操作系统上进行了测试:ubuntu-20.04、ubuntu-18.04、windows-2022、windows-2019、windows-2016、macos-11、macos-10.15,以及以下PHP版本:8.0、7.4、7.3、7.2、7.1、7.0。

以下是PHP测试类:
https://github.com/rosell-dk/exec-with-fallback/blob/main/tests/LineSplittingTest.php

并且此项目成功运行了这些测试:
https://github.com/rosell-dk/exec-with-fallback/actions/runs/1520070091

Javascript演示原理
以下是一些类似的正则表达式的javascript演示(我使用N和R代替\n和\r)。

保留换行演示:https://regexr.com/6ahvl
移除换行演示:https://regexr.com/6ai0j

附注:目前regexr存在一个错误,会在首次加载时显示“错误”。修改表达式即可消除错误。


8

对于换行,只需使用

$list = explode("\n", $text);

如果需要换行和回车(例如Windows文件),可以按照您发布的方式进行。 您的skuList是一个文本区域吗?


8

\n放在双引号中:

explode("\n", $_POST['skuList']);

如果我没记错的话,在单引号中,这会被视为\n分别处理。


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