参照:これは自己回答の質問です。知識、Q&Aスタイルを共有することを目的としていました。
PHPで行末文字のタイプを検出するにはどうすればよいですか?
PS:私はこのコードを最初から書いているのが長すぎるので、SOで共有することにしました。さらに、誰かが改善の方法を見つけると確信しています。
/**
* 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;
}
ノート:
mb_detect_eol()
(マルチバイト)およびdetect_eol()
正規表現を使用して新しい行を除くすべてを置き換える方が簡単ではないでしょうか?
ドットは、その文字が何であるかを気にせずに、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);
正規表現がこれらすべてを行うことを信頼できるかどうかはわかりませんが、テストするものは何もありません.
ここで既に与えられた回答は、ユーザーに十分な情報を提供します。次のコード(すでに与えられた答えに基づく)はさらに役立つかもしれません:
/**
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を実装クラス (すべての静的メンバー) の名前に変更します。
私の答えは、オハールの作品もトランシルヴラッドの作品も作ることができなかったので、次のとおりです。
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 つの点を考慮する必要があります。
.*
の提案どおりに使用しても機能しません。が改行文字と一致しないのは事実ですが、改行文字または改行文字の一部ではないシステムでは、正しく一致しません (注意: システム上の改行とは異なる可能性があるため、改行を検出しています. それ以外の場合は意味がありません)。.
\r
.
/[^\r\n]*/
と、テキストが消えるように「機能」しますが、セパレーターが必要になるとすぐに問題になります(改行以外のすべての文字を削除するため、改行以外の文字は有効なセパレーターになります) )。したがって、改行との一致を作成し、置換でその一致への後方参照を使用するという考えです。