回车和换行
关于行尾不一致原因简单解释下:这是由Windows和Unix不同的标准引起的,即“回车”和“换行”的问题。“回车”和“换行”是ASCII字符集中两个不可
见的控制符。
名称 | 英文单词 | 简写 | ASCII码十进制 | ASCII码十六进制 | C#string表示 |
回车 | Carriage Return | CR | 13 | 0x0d | "\r" |
换行 | Line - Feed | LF | 10 | 0x0a | "\n" |
回车换行 | Carriage - Return Line - Feed | CRLF | 1310 | 0x0d 0x0a | "\r\n" |
来源于打字机,
回车:告诉打字机把打印头定位在左边界
换行:告诉打字机把纸向下移一行
在Unix中“回车”不换行,“换行”才换行,行尾只需要一个“换行”,
在Windows中,“回车”和“换行”都换行,“回车”+“换行”才是行尾,所以符合Windows开发标准的文本编辑器才会提醒你
当前编辑的文本不符合Windows行尾标准。
在C#中应用
"\r\n"回车换行符是不可见字符,因为它没有符号,只有在16进制才能看到它,但是它起到换行的作用。
可见字符,是指在打开的txt文件或者编译器输出窗口看到的字符,它是没有回车换行的作用。
可见的字符"\r\n",在C#字符串中是用"\\r\\n"表示,string visibleSign ="\\r\\n";(不起换行的作用,只是用来显示字符本身"\r\n")
不可见字符"\r\n",在C#字符串中是用"\r\n"表示,string newLine = "\r\n";(起到换行的作用)
区别
string newLine = "\r\n";//不可见字符,回车换行符
string visibleSign = "\\r\\n"; //可见字符
byte[] bytes_newLine= Encoding.UTF8.GetBytes(newLine);
byte[] bytes_visibleSign = Encoding.UTF8.GetBytes(visibleSign);
string hexOutput = "";
for (int i = 0; i < bytes_newLine.Length; i++)
{
hexOutput += "0x" + bytes_newLine[i].ToString("X2") + ","; //转换成16进制字符串
}
Console.WriteLine("============bytes_newLine============");
Console.WriteLine(hexOutput);//0x0D,0x0A
hexOutput = "";
for (int i = 0; i < bytes_visibleSign.Length; i++)
{
hexOutput += "0x" + bytes_visibleSign[i].ToString("X2") + ","; //转换成16进制字符串
}
Console.WriteLine("=========bytes_visibleSign===============");
Console.WriteLine(hexOutput); //0x5C ,0x72 ,0x5C ,0x6E
互转
//不可见字符 转 可见
string newLine = "\r\n";//不可见字符,回车换行符
if (Regex.Escape(newLine) == "\\r\\n")
{
//true
}
// 可见 转 不可见字符
string visibleSign = "\\r\\n"; //可见字符
visibleSign = VisibleSignToNewLine(visibleSign);
if (visibleSign == "\r\n")
{
//true
}
/// <summary>
/// 可见字符转不可见字符,,把visibleSign内所有替换 "\\r\\n" => "\r\n"
/// </summary>
/// <param name="visibleSign"></param>
/// <returns></returns>
string VisibleSignToNewLine(string visibleSign)
{
byte byte_5c = Convert.ToByte("0x5C", 16);
byte byte_72 = Convert.ToByte("0x72", 16);
byte byte_6e = Convert.ToByte("0x6e", 16);
byte byte_0d = Convert.ToByte("0x0d", 16);//\r
byte byte_0a = Convert.ToByte("0x0a", 16);//\n
byte[] bytes_visibleSign = Encoding.UTF8.GetBytes(visibleSign);
List<byte> bs = new List<byte>();
for (int i = 0; i < bytes_visibleSign.Length; i++)
{
if (i + 3 < bytes_visibleSign.Length
&& bytes_visibleSign[i] == byte_5c
&& bytes_visibleSign[i + 1] == byte_72
&& bytes_visibleSign[i + 2] == byte_5c
&& bytes_visibleSign[i + 3] == byte_6e)
{
bs.Add(byte_0d);
bs.Add(byte_0a);
i += 3;
continue;
}
bs.Add(bytes_visibleSign[i]);
}
visibleSign = Encoding.GetEncoding("UTF-8").GetString(bs.ToArray());
return visibleSign;
}
/// <summary>
/// 可见字符转不可见字符,把visibleSign内所有替换 "\\r\\n" => "\n"
/// </summary>
/// <param name="visibleSign"></param>
/// <returns></returns>
string VisibleSignToNewLineN(string visibleSign)
{
byte byte_5c = Convert.ToByte("0x5C", 16);
byte byte_72 = Convert.ToByte("0x72", 16);
byte byte_6e = Convert.ToByte("0x6e", 16);
byte byte_0a = Convert.ToByte("0x0a", 16);//\n
byte[] bytes_visibleSign = Encoding.UTF8.GetBytes(visibleSign);
List<byte> bs = new List<byte>();
for (int i = 0; i < bytes_visibleSign.Length; i++)
{
if (i + 3 < bytes_visibleSign.Length
&& bytes_visibleSign[i] == byte_5c
&& bytes_visibleSign[i + 1] == byte_72
&& bytes_visibleSign[i + 2] == byte_5c
&& bytes_visibleSign[i + 3] == byte_6e)
{
bs.Add(byte_0a);
i += 3;
continue;
}
bs.Add(bytes_visibleSign[i]);
}
visibleSign = Encoding.GetEncoding("UTF-8").GetString(bs.ToArray());
return visibleSign;
}