使用PHP检测EOL类型

Chr*_*ian 11 php platform newline

参考:这是一个自我回答的问题.它旨在分享知识,问答风格.

如何在PHP中检测行尾字符的类型?

PS:我从头开始编写这段代码的时间太长了,所以我决定在SO上分享它,而且,我相信有人会找到改进的方法.

Chr*_*ian 8

/**
 * Detects the end-of-line character of a string.
 * @param string $str The string to check.
 * @param string $default Default EOL (if not detected).
 * @return string The detected EOL, or default one.
 */
function detectEol($str, $default=''){
    static $eols = array(
        "\0x000D000A", // [UNICODE] CR+LF: CR (U+000D) followed by LF (U+000A)
        "\0x000A",     // [UNICODE] LF: Line Feed, U+000A
        "\0x000B",     // [UNICODE] VT: Vertical Tab, U+000B
        "\0x000C",     // [UNICODE] FF: Form Feed, U+000C
        "\0x000D",     // [UNICODE] CR: Carriage Return, U+000D
        "\0x0085",     // [UNICODE] NEL: Next Line, U+0085
        "\0x2028",     // [UNICODE] LS: Line Separator, U+2028
        "\0x2029",     // [UNICODE] PS: Paragraph Separator, U+2029
        "\0x0D0A",     // [ASCII] CR+LF: Windows, TOPS-10, RT-11, CP/M, MP/M, DOS, Atari TOS, OS/2, Symbian OS, Palm OS
        "\0x0A0D",     // [ASCII] LF+CR: BBC Acorn, RISC OS spooled text output.
        "\0x0A",       // [ASCII] LF: Multics, Unix, Unix-like, BeOS, Amiga, RISC OS
        "\0x0D",       // [ASCII] CR: Commodore 8-bit, BBC Acorn, TRS-80, Apple II, Mac OS <=v9, OS-9
        "\0x1E",       // [ASCII] RS: QNX (pre-POSIX)
        //"\0x76",       // [?????] NEWLINE: ZX80, ZX81 [DEPRECATED]
        "\0x15",       // [EBCDEIC] NEL: OS/390, OS/400
    );
    $cur_cnt = 0;
    $cur_eol = $default;
    foreach($eols as $eol){
        if(($count = substr_count($str, $eol)) > $cur_cnt){
            $cur_cnt = $count;
            $cur_eol = $eol;
        }
    }
    return $cur_eol;
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 需要检查编码类型
  • 需要以某种方式知道我们可能在ZX8x之类的异域系统上(因为ASCII x76是常规字母) @radu提出了一个好点,在我的情况下,不值得努力处理ZX8x系统.
  • 我应该将功能分成两部分吗? mb_detect_eol()(多字节)和detect_eol()

  • @Christian,如果这些(非常)旧系统不是主要关注点,我认为安全性比抱歉更好.否则,可能在应用此方法之前尝试确定文档的编码. (2认同)

oha*_*aal 6

使用正则表达式替换除新行之外的所有内容会不会更容易?

该点匹配单个字符,而不关心该字符是什么.唯一的例外是换行符.

考虑到这一点,我们做了一些魔术:

$string = 'some string with new lines';
$newlines = preg_replace('/.*/', '', $string);
// $newlines is now filled with new lines, we only need one
$newline = substr($newlines, 0, 1);
Run Code Online (Sandbox Code Playgroud)

不确定我们是否可以信任正则表达式来完成所有这些,但我没有任何可测试的东西.

在此输入图像描述

  • 默认情况下,正则表达式认为"换行符"仅为\n.(这可以通过构建选项进行更改).但是我确实找到了一个正在上面而不是'/.*/'的正则表达式,它是'/(*ANYCRLF)./'.这里有关于正则表达式和行结尾的非常好的文章:https://nikic.github.io/2011/12/10/PCRE-and-newlines.html (2认同)