13

参照:これは自己回答の質問です。知識、Q&Aスタイルを共有することを目的としていました。

PHPで行末文字のタイプを検出するにはどうすればよいですか?

PS:私はこのコードを最初から書いているのが長すぎるので、SOで共有することにしました。さらに、誰かが改善の方法を見つけると確信しています。

4

7 に答える 7

9
/**
 * 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;
}

ノート:

  • エンコーディングタイプを確認する必要があります
  • ZX8xのようなエキゾチックなシステムを使用している可能性があることをどういうわけか知る必要があります(ASCII x76は通常の文字であるため) @raduは良い点を挙げました。私の場合、ZX8xシステムをうまく処理する価値はありません。
  • 関数を2つに分割する必要がありますか? mb_detect_eol()(マルチバイト)およびdetect_eol()
于 2012-06-16T20:38:20.450 に答える
7

正規表現を使用して新しい行を除くすべてを置き換える方が簡単ではないでしょうか?

ドットは、その文字が何であるかを気にせずに、1 つの文字に一致します。唯一の例外は改行文字です。

それを念頭に置いて、いくつかの魔法を行います。

$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);

正規表現がこれらすべてを行うことを信頼できるかどうかはわかりませんが、テストするものは何もありません.

ここに画像の説明を入力

于 2012-06-17T02:37:12.087 に答える
4

ここで既に与えられた回答は、ユーザーに十分な情報を提供します。次のコード(すでに与えられた答えに基づく)はさらに役立つかもしれません:

  • 見つかった EOL の参照を提供します
  • 検出は、アプリケーションが使用できるキーもこの参照に設定します。
  • ユーティリティ クラスで参照を使用する方法を示します。
  • 見つかった EOL のキー名を返すファイルの検出に使用する方法を示します。
  • 皆様のお役に立てれば幸いです。

    /**
    Newline characters in different Operating Systems
    The names given to the different sequences are:
    ============================================================================================
    NewL  Chars       Name     Description
    ----- ----------- -------- ------------------------------------------------------------------
    LF    0x0A        UNIX     Apple OSX, UNIX, Linux
    CR    0x0D        TRS80    Commodore, Acorn BBC, ZX Spectrum, TRS-80, Apple II family, etc
    LFCR  0x0A 0x0D   ACORN    Acorn BBC and RISC OS spooled text output.
    CRLF  0x0D 0x0A   WINDOWS  Microsoft Windows, DEC TOPS-10, RT-11 and most other early non-Unix
                              and non-IBM OSes, CP/M, MP/M, DOS (MS-DOS, PC DOS, etc.), OS/2,
    ----- ----------- -------- ------------------------------------------------------------------
    */
    const EOL_UNIX    = 'lf';        // Code: \n
    const EOL_TRS80   = 'cr';        // Code: \r
    const EOL_ACORN   = 'lfcr';      // Code: \n \r
    const EOL_WINDOWS = 'crlf';      // Code: \r \n
    

    次に、静的クラス Utility で次のコードを使用して検出します

    /**
    Detects the end-of-line character of a string.
    @param string $str      The string to check.
    @param string $key      [io] Name of the detected eol key.
    @return string The detected EOL, or default one.
    */
    public static function detectEOL($str, &$key) {
       static $eols = array(
         Util::EOL_ACORN   => "\n\r",  // 0x0A - 0x0D - acorn BBC
         Util::EOL_WINDOWS => "\r\n",  // 0x0D - 0x0A - Windows, DOS OS/2
         Util::EOL_UNIX    => "\n",    // 0x0A -      - Unix, OSX
         Util::EOL_TRS80   => "\r",    // 0x0D -      - Apple ][, TRS80
      );
    
      $key = "";
      $curCount = 0;
      $curEol = '';
      foreach($eols as $k => $eol) {
         if( ($count = substr_count($str, $eol)) > $curCount) {
            $curCount = $count;
            $curEol = $eol;
            $key = $k;
         }
      }
      return $curEol;
    }  // detectEOL
    

    次に、ファイルの場合:

    /**
    Detects the EOL of an file by checking the first line.
    @param string  $fileName    File to be tested (full pathname).
    @return boolean false | Used key = enum('cr', 'lf', crlf').
    @uses detectEOL
    */
    public static function detectFileEOL($fileName) {
       if (!file_exists($fileName)) {
         return false;
       }
    
       // Gets the line length
       $handle = @fopen($fileName, "r");
       if ($handle === false) {
          return false;
       }
       $line = fgets($handle);
       $key = "";
       <Your-Class-Name>::detectEOL($line, $key);
    
       return $key;
    }  // detectFileEOL
    

    Your-Class-Nameを実装クラス (すべての静的メンバー) の名前に変更します。

    于 2014-07-24T07:12:32.983 に答える
    3

    私の答えは、オハールの作品もトランシルヴラッドの作品も作ることができなかったので、次のとおりです。

    function detect_newline_type($content) {
        $arr = array_count_values(
                   explode(
                       ' ',
                       preg_replace(
                           '/[^\r\n]*(\r\n|\n|\r)/',
                           '\1 ',
                           $content
                       )
                   )
               );
        arsort($arr);
        return key($arr);
    }
    

    説明:

    提案された両方のソリューションの一般的な考え方は良いですが、実装の詳細がこれらの回答の有用性を妨げています。

    実際、この関数のポイントは、ファイルで使用されている改行の種類を返すことであり、その改行は 1 文字または 2 文字の長さです。

    これだけでも、の使用はstr_split()正しくありません。トークンを正しくカットする唯一の方法は、代わりに文字検出に基づいて可変長の文字列をカットする関数を使用することです。そんな時、explode()出番です。

    しかし、便利なマーカーを爆発させるには、適切な文字を適切な量で、適切な一致に置き換える必要があります。そして、魔法のほとんどは正規表現で起こります。

    3 つの点を考慮する必要があります。

    1. ohaal.*の提案どおりに使用しても機能しません。が改行文字と一致しないのは事実ですが、改行文字または改行文字の一部ではないシステムでは、正しく一致しません (注意: システム上の改行とは異なる可能性があるため、改行を検出しています. それ以外の場合は意味がありません)。.\r.
    2. 何かに置き換える/[^\r\n]*/と、テキストが消えるように「機能」しますが、セパレーターが必要になるとすぐに問題になります(改行以外のすべての文字を削除するため、改行以外の文字は有効なセパレーターになります) )。したがって、改行との一致を作成し、置換でその一致への後方参照を使用するという考えです。
    3. コンテンツでは、複数の改行が連続する可能性があります。ただし、コードの残りの部分からは異なるタイプの改行として認識されるため、その場合はグループ化したくありません。そのため、後方参照の一致で改行のリストが明示的に記述されています。
    于 2016-10-24T20:33:09.970 に答える