Sự khác biệt giữa \ r và \ n là gì?


245

Làm thế nào \r\nkhác nhau? Tôi nghĩ rằng nó có liên quan đến Unix so với Windows so với Mac, nhưng tôi không chắc chính xác chúng khác nhau như thế nào và tìm kiếm / kết hợp trong regexes.


1
Điều này cần một thẻ ngôn ngữ. Các ngôn ngữ khác nhau có cách giải thích khác nhau '\n'.
Adrian McCarthy

Câu trả lời:


383

Họ là những nhân vật khác nhau. \rlà vận chuyển trở lại, và \nlà nguồn cấp dữ liệu.

Trên các máy in "cũ", \rgửi đầu in trở lại đầu dòng và \nnâng giấy lên một dòng. Cả hai đều cần thiết để bắt đầu in trên dòng tiếp theo.

Rõ ràng điều đó bây giờ có phần không liên quan, mặc dù tùy thuộc vào bảng điều khiển, bạn vẫn có thể sử dụng \rđể di chuyển đến đầu dòng và ghi đè lên văn bản hiện có.

Quan trọng hơn, Unix có xu hướng sử dụng \nnhư một dấu tách dòng; Windows có xu hướng sử dụng \r\nnhư một trình phân tách dòng và máy Mac (tối đa OS 9) được sử dụng để \rphân tách dòng. (Mac OS X là Unix-y, vì vậy sử dụng \nthay thế; có thể có một số tình huống tương thích \rđược sử dụng thay thế.)

Để biết thêm thông tin, xem bài viết mới Wikipedia .

EDIT: Đây là ngôn ngữ nhạy cảm. Ví dụ, trong C # và Java, \n luôn có nghĩa là Unicode U + 000A, được định nghĩa là nguồn cấp dữ liệu. Trong C và C ++, nước có phần lầy hơn, vì ý nghĩa là đặc thù của nền tảng. Xem ý kiến ​​để biết chi tiết.


22
+1 cho người già. Đầu ra thiết bị đầu cuối được sử dụng để điều khiển trực tiếp thiết bị đầu cuối điện tử được tôn vinh (TTY của bạn trước khi các CRT ưa thích đó hiển thị). Do đó, chúng tôi nhận được các tạo tác tuyệt vời của những người trong xe ngựa và các nhân vật dòng mới (cả hai đều có thể cần thiết, như Jon Skeet đã đề cập) và những thứ như \ a "chuông", \ b "backspace" (không bị nhầm lẫn với "xóa ") Và tất cả các ký tự điều khiển khác cần để giao tiếp với một tty.
erjiang

35
+1 khác cho người già. Bạn vẫn có thể nhấn Ctrl + G trên dấu nhắc lệnh của windows, nhấn enter và loa PC sẽ phát ra tiếng bíp. Điều đó còn sót lại từ thời cổ đại.
Dave Carlile

@Crappy Coding Guy thực sự? Trên Vista, nó chỉ nói "'' không được công nhận là lệnh nội bộ hoặc bên ngoài"
Ponkadoodle

2
@AdrianMcCarthy: Tất nhiên câu hỏi không thực sự chỉ định C hoặc C ++ ở đây. Trong C #, ví dụ \n được đảm bảo là dòng mới (phần 2.4.4.4). Tất nhiên, sẽ rất tuyệt nếu OP đã chỉ định nền tảng ... Bên cạnh đó, tôi nghĩ mức độ chi tiết này sẽ khó hiểu hơn là hữu ích cho ai đó chỉ hỏi sự khác biệt.
Jon Skeet

2
@AdrianMcCarthy: Nhưng ít nhất trong C # và Java, nó nguồn cấp dữ liệu. Đó là U + 000A, được Unicode đặt tên là "LINE FEED" (và LINE MỚI). Tôi sẽ chỉnh sửa để đề cập đến trường hợp đặc biệt của C và C ++, nhưng tôi thực sự tin rằng đó những trường hợp đặc biệt chứ không phải ngược lại.
Jon Skeet

91

Trong C và C ++, \nlà một khái niệm, \rlà một ký tự và \r\n(hầu như luôn luôn) là một lỗi di động.

Hãy nghĩ về một teletype cũ. Đầu in được định vị trên một số dòng và trong một số cột. Khi bạn gửi một ký tự có thể in tới teletype, nó sẽ in ký tự đó ở vị trí hiện tại và di chuyển đầu đến cột tiếp theo. (Đây là khái niệm giống như một máy đánh chữ, ngoại trừ việc máy chữ thường di chuyển giấy đối với đầu in.)

Khi bạn muốn hoàn thành dòng hiện tại và bắt đầu dòng tiếp theo, bạn phải thực hiện hai bước riêng biệt:

  1. di chuyển đầu in trở lại đầu dòng, sau đó
  2. di chuyển nó xuống dòng tiếp theo.

ASCII mã hóa các hành động này dưới dạng hai ký tự điều khiển riêng biệt:

  • \x0D(CR) di chuyển đầu in trở lại đầu dòng. (Unicode mã hóa cái này là U+000D CARRIAGE RETURN.)
  • \x0A(LF) di chuyển đầu in xuống dòng tiếp theo. (Unicode mã hóa cái này là U+000A LINE FEED.)

Trong thời của teletypes và máy in công nghệ đầu tiên, mọi người thực sự đã tận dụng thực tế rằng đây là hai hoạt động riêng biệt. Bằng cách gửi CR mà không theo dõi nó bởi một LF, bạn có thể in qua dòng bạn đã in. Điều này cho phép các hiệu ứng như dấu, kiểu in đậm và gạch chân. Một số hệ thống được in đè nhiều lần để ngăn mật khẩu hiển thị trong bản cứng. Trên các thiết bị đầu cuối CRT nối tiếp ban đầu, CR là một trong những cách để kiểm soát vị trí con trỏ để cập nhật văn bản đã có trên màn hình.

Nhưng hầu hết thời gian, bạn thực sự chỉ muốn đi đến dòng tiếp theo. Thay vì yêu cầu cặp ký tự điều khiển, một số hệ thống chỉ cho phép cái này hoặc cái kia. Ví dụ:

  • Các biến thể Unix (bao gồm cả các phiên bản hiện đại của Mac) chỉ sử dụng một ký tự LF để chỉ ra một dòng mới.
  • Các tệp Macintosh cũ (tiền OSX) chỉ được sử dụng ký tự CR để chỉ ra một dòng mới.
  • VMS, CP / M, DOS, Windows và nhiều giao thức mạng vẫn mong đợi cả hai: CR LF.
  • Các hệ thống cũ của IBM đã sử dụng EBCDIC được tiêu chuẩn hóa trên NL - một ký tự thậm chí không tồn tại trong bộ ký tự ASCII. Trong Unicode, NL là U+0085 NEXT LINE, nhưng giá trị EBCDIC thực tế là 0x15.

Tại sao các hệ thống khác nhau chọn các phương pháp khác nhau? Đơn giản vì không có tiêu chuẩn chung. Trường hợp bàn phím của bạn có thể nói "Enter", bàn phím cũ hơn được sử dụng để nói "Trả lại", viết tắt của từ Vận chuyển. Trong thực tế, trên một thiết bị đầu cuối nối tiếp, nhấn Return thực sự sẽ gửi ký tự CR. Nếu bạn đang viết một trình soạn thảo văn bản, sẽ rất hấp dẫn nếu chỉ sử dụng ký tự đó khi nó đến từ thiết bị đầu cuối. Có lẽ đó là lý do tại sao các máy Mac cũ chỉ sử dụng CR.

Bây giờ chúng ta có các tiêu chuẩn , có nhiều cách hơn để biểu diễn các ngắt dòng. Mặc dù cực kỳ hiếm trong tự nhiên, Unicode có các ký tự mới như:

  • U+2028 LINE SEPARATOR
  • U+2029 PARAGRAPH SEPARATOR

Ngay cả trước khi Unicode xuất hiện, các lập trình viên muốn có những cách đơn giản để biểu diễn một số mã điều khiển hữu ích nhất mà không phải lo lắng về bộ ký tự cơ bản. C có một số chuỗi thoát để biểu diễn mã kiểm soát:

  • \a (để cảnh báo) rung chuông teletype hoặc làm cho thiết bị đầu cuối phát ra tiếng bíp
  • \f (đối với nguồn cấp dữ liệu mẫu) di chuyển đến đầu trang tiếp theo
  • \t (đối với tab) di chuyển đầu in sang vị trí tab ngang tiếp theo

(Danh sách này là không đầy đủ có chủ ý.)

Ánh xạ này xảy ra vào thời gian biên dịch - trình biên dịch nhìn thấy \avà đặt bất kỳ giá trị ma thuật nào được sử dụng để rung chuông.

Lưu ý rằng hầu hết các bản ghi nhớ này có mối tương quan trực tiếp với mã kiểm soát ASCII. Ví dụ, \asẽ ánh xạ tới 0x07 BEL. Một trình biên dịch có thể được viết cho một hệ thống sử dụng một cái gì đó không phải ASCII cho bộ ký tự máy chủ (ví dụ: EBCDIC). Hầu hết các mã điều khiển có khả năng ghi nhớ cụ thể có thể được ánh xạ thành mã kiểm soát trong các bộ ký tự khác.

Huzzah! Tính di động!

Vâng, gần như vậy. Trong C, tôi có thể viết printf("\aHello, World!");những tiếng chuông (hoặc tiếng bíp) và phát ra một thông báo. Nhưng nếu tôi muốn sau đó in một cái gì đó trên dòng tiếp theo, tôi vẫn cần biết nền tảng máy chủ yêu cầu gì để chuyển sang dòng đầu ra tiếp theo. CR CR? LF? NL? Thứ gì khác? Quá nhiều cho tính di động.

C có hai chế độ cho I / O: nhị phân và văn bản. Trong chế độ nhị phân, bất kỳ dữ liệu nào được gửi đều được truyền đi. Nhưng trong chế độ văn bản, có một bản dịch thời gian thực chuyển đổi một ký tự đặc biệt thành bất cứ thứ gì nền tảng máy chủ cần cho một dòng mới (và ngược lại).

Tuyệt, vậy nhân vật đặc biệt là gì?

Chà, điều đó cũng phụ thuộc vào việc triển khai, nhưng có một cách độc lập với việc triển khai để chỉ định nó : \n. Nó thường được gọi là "nhân vật dòng mới".

Đây là một điểm tinh tế nhưng quan trọng: \n được ánh xạ tại thời điểm biên dịch thành giá trị ký tự do xác định thực hiện , sau đó (ở chế độ văn bản) sẽ được ánh xạ lại vào thời gian chạy tới ký tự thực (hoặc chuỗi ký tự) được yêu cầu bởi nền tảng bên dưới để di chuyển đến dòng tiếp theo.

\nkhác với tất cả các nghĩa đen gạch chéo khác vì có hai ánh xạ liên quan. Ánh xạ hai bước này tạo ra \nsự khác biệt đáng kể so với chẵn \r, chỉ đơn giản là ánh xạ thời gian biên dịch sang CR (hoặc mã điều khiển tương tự nhất trong bất kỳ bộ ký tự cơ bản nào).

Điều này làm tăng nhiều lập trình viên C và C ++. Nếu bạn đã bỏ phiếu 100 trong số họ, ít nhất 99 sẽ cho bạn biết điều đó \ncó nghĩa là nguồn cấp dữ liệu. Điều này không hoàn toàn đúng. Hầu hết (có lẽ là tất cả) các triển khai C và C ++ sử dụng LF làm giá trị trung gian kỳ diệu cho \n, nhưng đó là một chi tiết triển khai. Việc trình biên dịch sử dụng một giá trị khác là khả thi. Trên thực tế, nếu bộ ký tự máy chủ không phải là siêu ký tự của ASCII (ví dụ: nếu là EBCDIC), thì \ngần như chắc chắn sẽ không phải là LF.

Vì vậy, trong C và C ++:

  • \r nghĩa đen là một sự trở lại xe ngựa.
  • \nlà một giá trị ma thuật được dịch (ở chế độ văn bản) tại thời điểm chạy đến / từ ngữ nghĩa dòng mới của nền tảng máy chủ.
  • \r\nhầu như luôn luôn là một lỗi di động. Trong chế độ văn bản, điều này được dịch sang CR theo sau là chuỗi dòng mới của nền tảng - có thể không phải là mục đích. Trong chế độ nhị phân, điều này được dịch sang CR theo sau là một số giá trị ma thuật có thể không phải là LF - có thể không phải là mục đích.
  • \x0Alà cách dễ mang theo nhất để chỉ ra ASCII LF, nhưng bạn chỉ muốn làm điều đó ở chế độ nhị phân. Hầu hết các cài đặt chế độ văn bản sẽ đối xử như thế \n.

Đi qua bài đăng này trong khi cố gắng tìm ra cách phân tách đầu vào <textarea> trong Python và \r\nthực sự là cách duy nhất tôi có thể phân chia các dòng thành các thành phần danh sách riêng biệt. Nó khiến tôi tự hỏi liệu đây có phải là một tạo phẩm HTML kỳ lạ hay không, hay nó có liên quan đến cách Python ăn chuỗi từ requestđối tượng của tôi không .
Pat Jones

11
  • "\ r" => Trả lại
  • "\ n" => Dòng mới hoặc Linefeed (ngữ nghĩa)

  • Các hệ thống dựa trên Unix chỉ sử dụng "\ n" để kết thúc một dòng văn bản.

  • Dos sử dụng "\ r \ n" để kết thúc một dòng văn bản.
  • Một số máy khác chỉ sử dụng "\ r". (Commodore, Apple II, Mac OS trước OS X, v.v.)

5

\r được sử dụng để trỏ đến điểm bắt đầu của một dòng và có thể thay thế văn bản từ đó, ví dụ:

main()
{
printf("\nab");
printf("\bsi");
printf("\rha");
}

Sản xuất đầu ra này:

hai

\n là cho dòng mới.


4

Nói tóm lại, \ r có giá trị ASCII 13 (CR) và \ n có giá trị ASCII 10 (LF). Mac sử dụng CR làm dấu phân cách dòng (ít nhất, nó đã làm trước đây, tôi không chắc chắn cho các máy Mac hiện đại), * nix sử dụng LF và Windows sử dụng cả hai (CRLF).


1
Các hệ thống Mac OS X sử dụng LF theo mặc định (vì nó dựa trên BSD Unix).
dreamlax

3

Ngoài câu trả lời của @Jon Skeet:

Theo truyền thống, Windows đã sử dụng \ r \ n, Unix \ n và Mac \ r, tuy nhiên các máy Mac mới hơn sử dụng \ n vì chúng không dựa trên cơ sở.


2

trong C # tôi thấy họ sử dụng \ r \ n trong một chuỗi.


2

\ r là Vận chuyển trở lại; \ n là Dòng mới (Nguồn cấp dữ liệu) ... tùy thuộc vào hệ điều hành cho từng phương tiện. Đọc bài viết này để biết thêm về sự khác biệt giữa '\ n' và '\ r \ n' ... trong C.


1

\ r được sử dụng để vận chuyển trở lại. (Giá trị ASCII là 13) \ n được sử dụng cho dòng mới. (Giá trị ASCII là 10)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.