อะไรคือความแตกต่างระหว่าง \ r และ \ n?


245

เป็นอย่างไร\rและ\nแตกต่างกันอย่างไร ฉันคิดว่ามันเกี่ยวกับ Unix กับ Windows กับ Mac แต่ฉันไม่แน่ใจว่ามันแตกต่างกันอย่างไรและจะค้นหา / จับคู่ใน regexes ได้อย่างไร


1
ต้องใช้แท็กภาษา '\n'ภาษาที่แตกต่างกันมีการตีความที่แตกต่างกันของ
Adrian McCarthy

คำตอบ:


383

พวกเขาเป็นตัวละครที่แตกต่างกัน \rคือการขึ้น\nบรรทัดใหม่และเป็นตัวดึงข้อมูลบรรทัด

บนเครื่องพิมพ์ "เก่า" \rส่งหัวพิมพ์กลับไปที่จุดเริ่มต้นของบรรทัดและ\nขั้นสูงกระดาษหนึ่งบรรทัด ทั้งคู่จึงจำเป็นต้องเริ่มพิมพ์ในบรรทัดถัดไป

เห็นได้ชัดว่าตอนนี้ไม่เกี่ยวข้องเลยแม้ว่าจะขึ้นอยู่กับคอนโซลคุณอาจยังสามารถใช้\rเพื่อย้ายไปที่จุดเริ่มต้นของบรรทัดและเขียนทับข้อความที่มีอยู่

ที่สำคัญกว่ายูนิกซ์มีแนวโน้มที่จะใช้\nเป็นตัวแยกบรรทัด หน้าต่างมีแนวโน้มที่จะใช้\r\nเป็นตัวคั่นบรรทัดและแม็ค (ถึง OS 9) ที่ใช้กับการใช้\rเป็นตัวคั่นบรรทัด (Mac OS X คือ Unix-y ดังนั้นควรใช้\nแทน แต่อาจมีสถานการณ์ความเข้ากันได้บางอย่างที่\rใช้แทน)

สำหรับข้อมูลเพิ่มเติมโปรดดูที่บทความวิกิพีเดียขึ้นบรรทัดใหม่

แก้ไข: นี่คือภาษาที่ละเอียดอ่อน ใน C # และ Java ตัวอย่างเช่น\n มักจะหมายถึง Unicode U + 000A ซึ่งถูกกำหนดให้เป็นอาหารเส้น ใน C และ C ++ น้ำค่อนข้าง muddier เป็นความหมายเฉพาะแพลตฟอร์ม ดูความคิดเห็นเพื่อดูรายละเอียด


22
+1 สำหรับคนชรา เทอร์มินัลเอาท์พุทใช้สำหรับควบคุมเทอร์มินัลอิเล็กทรอนิกส์ที่ได้รับการยกย่องโดยตรง (TTY ของคุณก่อนหน้าจอ CRT แฟนซีเหล่านั้น) ดังนั้นเราจึงได้รับสิ่งประดิษฐ์ที่ยอดเยี่ยมของตัวละครในการขึ้นบรรทัดใหม่และอักขระขึ้นบรรทัดใหม่ (ซึ่งอาจจำเป็นทั้งสองอย่างตามที่ Jon Skeet กล่าวไว้) และสิ่งต่าง ๆ เช่น \ a "กระดิ่ง", \ b "backspace" (เพื่อไม่ให้สับสนกับ "ลบ" ") และอักขระควบคุมอื่น ๆ ทั้งหมดที่จำเป็นในการสื่อสารกับ tty
erjiang

35
อีก +1 สำหรับคนเก่า คุณยังสามารถกด Ctrl + G บนพรอมต์คำสั่ง windows กด Enter และลำโพง PC จะส่งเสียงบี๊บ ที่เหลือจากสมัยโบราณ
Dave Carlile

@ Crappy Coding Guy จริงเหรอ? ใน Vista มันเพิ่งบอกว่า "'' ไม่ได้รับการยอมรับว่าเป็นคำสั่งภายในหรือภายนอก"
Ponkadoodle

2
@AdrianMcCarthy: แน่นอนว่าคำถามไม่ได้ระบุ C หรือ C ++ ที่นี่จริงๆ ใน C #, ตัวอย่างเช่น\n มีการรับประกันว่าจะขึ้นบรรทัดใหม่ (มาตรา 2.4.4.4) แน่นอนว่ามันจะดีถ้า OP ได้ระบุแพลตฟอร์ม ... นอกจากนี้ฉันคิดว่ารายละเอียดในระดับนี้จะสับสนมากกว่าประโยชน์สำหรับใครบางคนที่ถามถึงความแตกต่าง
Jon Skeet

2
@AdrianMcCarthy: แต่อย่างน้อยใน C # และ Java อย่างน้อยก็เป็น line feed มันคือ U + 000A ซึ่งถูกตั้งชื่อโดย Unicode ว่า "LINE FEED" (และ NEW LINE) ฉันจะแก้ไขพูดถึงกรณีพิเศษของ C และ C ++ แต่ฉันเชื่ออย่างแท้จริงว่าเป็นกรณีพิเศษไม่ใช่อีกทางหนึ่ง
Jon Skeet

91

ใน C และ C ++ \nเป็นแนวคิด\rคืออักขระและ\r\n(เกือบทุกครั้ง) บั๊กความสามารถในการพกพา

คิดว่าโทรพิมพ์เก่า หัวพิมพ์อยู่ในตำแหน่งที่เหมาะสมในบางบรรทัดและในบางคอลัมน์ เมื่อคุณส่งอักขระที่พิมพ์ได้ไปยังโทรพิมพ์พิมพ์อักขระที่ตำแหน่งปัจจุบันและย้ายหัวไปยังคอลัมน์ถัดไป (นี่คือแนวคิดเหมือนกับเครื่องพิมพ์ดีดยกเว้นเครื่องพิมพ์ดีดมักจะย้ายกระดาษที่เกี่ยวกับหัวพิมพ์)

เมื่อคุณต้องการที่จะจบบรรทัดปัจจุบันและเริ่มต้นในบรรทัดถัดไปคุณต้องทำสองขั้นตอนแยกจากกัน:

  1. เลื่อนหัวพิมพ์กลับไปที่จุดเริ่มต้นของบรรทัดจากนั้น
  2. เลื่อนลงไปยังบรรทัดถัดไป

ASCII เข้ารหัสการกระทำเหล่านี้เป็นอักขระควบคุมสองตัวที่แตกต่างกัน:

  • \x0D(CR) เลื่อนหัวพิมพ์กลับไปที่จุดเริ่มต้นของบรรทัด (Unicode เข้ารหัสสิ่งนี้เป็นU+000D CARRIAGE RETURN.)
  • \x0A(LF) เลื่อนหัวพิมพ์ลงไปที่บรรทัดถัดไป (Unicode เข้ารหัสสิ่งนี้เป็นU+000A LINE FEED.)

ในยุคของโทรศัพท์และเครื่องพิมพ์เทคโนโลยียุคแรกผู้คนใช้ประโยชน์จากความจริงที่ว่าสิ่งเหล่านี้เป็นการดำเนินการแยกกันสองอย่าง โดยการส่ง CR โดยไม่ทำตามโดย LF คุณสามารถพิมพ์บนบรรทัดที่คุณพิมพ์ไปแล้ว เอฟเฟกต์ที่อนุญาตเช่นเน้นเสียง, ตัวหนา, และขีดเส้นใต้ ระบบบางระบบพิมพ์ทับหลาย ๆ ครั้งเพื่อป้องกันไม่ให้รหัสผ่านปรากฏในสำเนาถาวร สำหรับเทอร์มินัล CRT แบบอนุกรม CR เป็นวิธีหนึ่งในการควบคุมตำแหน่งเคอร์เซอร์เพื่ออัปเดตข้อความบนหน้าจอ

แต่ส่วนใหญ่แล้วคุณแค่อยากไปที่บรรทัดถัดไป แทนที่จะต้องการคู่ของอักขระควบคุมระบบบางระบบอนุญาตเพียงหนึ่งหรืออย่างอื่น ตัวอย่างเช่น:

  • ตัวแปร Unix (รวมถึง Mac รุ่นที่ทันสมัย) ใช้เพียงอักขระ LF เพื่อระบุบรรทัดใหม่
  • ไฟล์ Macintosh เก่า (pre-OSX) ใช้ตัวอักษร CR เพื่อระบุบรรทัดใหม่
  • VMS, CP / M, DOS, Windows และโปรโตคอลเครือข่ายจำนวนมากยังคงคาดหวังว่าทั้งสอง: CR LF
  • ระบบ IBM เก่าที่ใช้EBCDIC เป็นมาตรฐานบน NL - อักขระที่ไม่มีอยู่ในชุดอักขระ ASCII ใน Unicode, NL เป็นU+0085 NEXT LINEแต่ค่า EBCDIC 0x15ที่เกิดขึ้นจริง

ทำไมระบบที่แตกต่างกันถึงเลือกวิธีที่ต่างกัน เพียงเพราะไม่มีมาตรฐานสากล แป้นพิมพ์ของคุณอาจระบุว่า "Enter" แป้นพิมพ์ที่เก่ากว่าเคยพูดว่า "Return" ซึ่งย่อมาจาก Carriage Return ในความเป็นจริงบนเทอร์มินัลอนุกรมกด Return จริง ๆ ส่งอักขระ CR หากคุณกำลังเขียนโปรแกรมแก้ไขข้อความมันจะเป็นการดึงดูดให้ใช้ตัวละครนั้นเมื่อเข้ามาจากเครื่องเทอร์มินัล บางทีนั่นอาจเป็นเหตุผลที่ Mac รุ่นเก่าใช้เพียง CR

ตอนนี้เรามีมาตรฐานแล้วมีวิธีมากขึ้นในการเป็นตัวแบ่งบรรทัด แม้ว่า Unicode จะหายากมาก แต่ Unicode ก็มีตัวละครใหม่ ๆ เช่น:

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

ก่อนที่ Unicode จะเข้ามาโปรแกรมเมอร์ต้องการวิธีง่าย ๆ ในการแสดงรหัสควบคุมที่มีประโยชน์ที่สุดโดยไม่ต้องกังวลเกี่ยวกับชุดอักขระพื้นฐาน C มีหลายลำดับ escape สำหรับการแทนรหัสควบคุม:

  • \a (สำหรับการแจ้งเตือน) ซึ่งส่งเสียงสัญญาณโทรพิมพ์หรือส่งเสียงบี๊บ
  • \f (สำหรับฟีดฟอร์ม) ซึ่งย้ายไปที่จุดเริ่มต้นของหน้าถัดไป
  • \t (สำหรับแท็บ) ซึ่งย้ายหัวพิมพ์ไปยังตำแหน่งแท็บแนวนอนถัดไป

(รายการนี้ไม่สมบูรณ์โดยเจตนา)

การทำแผนที่นี้เกิดขึ้นในเวลารวบรวม - คอมไพเลอร์มองเห็น\aและกำหนดค่าวิเศษที่จะใช้เพื่อส่งสัญญาณเตือน

โปรดสังเกตว่าตัวช่วยจำส่วนใหญ่เหล่านี้มีความสัมพันธ์โดยตรงกับรหัสควบคุม ASCII ยกตัวอย่างเช่นจะแมปไป\a 0x07 BELคอมไพเลอร์สามารถเขียนสำหรับระบบที่ใช้อย่างอื่นที่ไม่ใช่ ASCII สำหรับชุดอักขระโฮสต์ (เช่น EBCDIC) รหัสควบคุมส่วนใหญ่ที่มีตัวช่วยจำเฉพาะสามารถแมปกับรหัสควบคุมในชุดอักขระอื่นได้

Huzzah! พกพา!

เกือบแล้ว ใน C ฉันสามารถเขียนprintf("\aHello, World!");เสียงกริ่ง (หรือส่งเสียงบี๊บ) ที่ส่งเสียงข้อความ แต่ถ้าฉันต้องการพิมพ์บางอย่างในบรรทัดถัดไปฉันยังต้องรู้ว่าแพลตฟอร์มโฮสต์ต้องการย้ายไปที่บรรทัดถัดไปของเอาต์พุต CR LF CR? LF? NL? อื่น ๆ อีก? มากสำหรับการพกพา

C มีสองโหมดสำหรับ I / O: ไบนารีและข้อความ ในโหมดไบนารีข้อมูลอะไรก็ตามที่ถูกส่งจะได้รับการส่งตามสภาพ แต่ในโหมดข้อความมีการแปลแบบรันไทม์ที่แปลงอักขระพิเศษเป็นสิ่งที่แพลตฟอร์มโฮสต์ต้องการสำหรับบรรทัดใหม่ (และในทางกลับกัน)

เยี่ยมมากแล้วตัวละครพิเศษคืออะไร?

ดีที่การดำเนินการขึ้นอยู่กับเกินไป \nแต่มีวิธีการดำเนินงานที่เป็นอิสระที่จะระบุว่า: โดยทั่วไปเรียกว่า "อักขระบรรทัดใหม่"

นี่เป็นจุดที่บอบบาง แต่สำคัญ: \nถูกแมป ณเวลารวบรวมกับค่าอักขระที่กำหนดการนำไปปฏิบัติซึ่ง (ในโหมดข้อความ) จะถูกแมปอีกครั้ง ณรันไทม์กับอักขระจริง (หรือลำดับของอักขระ) ที่ต้องการโดยแพลตฟอร์มพื้นฐานเพื่อย้าย ไปที่บรรทัดถัดไป

\nแตกต่างจากตัวอักษรแบ็กสแลชอื่น ๆ ทั้งหมดเนื่องจากมีการแมปสองรายการที่เกี่ยวข้อง การทำแผนที่สองขั้นตอนนี้ทำให้\nแตกต่างอย่างมีนัยสำคัญกว่าแม้กระทั่ง\rซึ่งเป็นเพียงการทำแผนที่รวบรวมเวลาเพื่อ CR (หรือรหัสควบคุมที่คล้ายกันมากที่สุดในสิ่งที่ชุดอักขระพื้นฐาน)

การเดินทางครั้งนี้ขึ้นโปรแกรมเมอร์ C และ C ++ มากมาย หากคุณต้องสำรวจ 100 คนอย่างน้อย 99 คนจะบอกคุณว่านั่น\nหมายถึงการป้อนบรรทัด สิ่งนี้ไม่เป็นความจริงทั้งหมด การใช้งาน C และ C ++ ส่วนใหญ่ (อาจจะทั้งหมด) ใช้ LF เป็นค่ากลางเวทมนต์สำหรับ\nแต่นั่นเป็นรายละเอียดการใช้งาน คอมไพเลอร์สามารถใช้ค่าอื่นได้ ในความเป็นจริงหากชุดอักขระโฮสต์ไม่ได้เป็นชุดของ ASCII (เช่นถ้าเป็น EBCDIC) ก็\nจะไม่เป็น LF แน่นอน

ดังนั้นใน C และ C ++:

  • \r คือการรับคืนอย่างแท้จริง
  • \nเป็นค่าเวทย์มนตร์ที่ได้รับการแปล (ในโหมดข้อความ) ณรันไทม์ไป / จากความหมายบรรทัดใหม่ของแพลตฟอร์มโฮสต์
  • \r\nมักจะเป็นข้อบกพร่องในการพกพา ในโหมดข้อความสิ่งนี้จะถูกแปลเป็น CR ตามด้วยลำดับบรรทัดใหม่ของแพลตฟอร์มซึ่งอาจไม่ใช่สิ่งที่ตั้งใจไว้ ในโหมดไบนารีสิ่งนี้จะถูกแปลเป็น CR ตามด้วยค่าเวทย์มนตร์ที่อาจไม่ใช่ LF - อาจไม่ใช่สิ่งที่ตั้งใจไว้
  • \x0Aเป็นวิธีพกพาที่สุดในการระบุ ASCII LF แต่คุณต้องการทำในโหมดไบนารี การใช้งานในโหมดข้อความส่วนใหญ่จะปฏิบัติเช่น\nนั้น

มาข้ามโพสต์นี้ขณะที่พยายามหาวิธีแยก <textarea> อินพุตใน Python และที่\r\nจริงแล้วเป็นวิธีเดียวที่ฉันสามารถแยกบรรทัดออกเป็นองค์ประกอบรายการแยกกันได้อย่างเหมาะสม มันทำให้ฉันสงสัยว่านี่เป็นสิ่งประดิษฐ์ HTML แปลก ๆ หรือว่าเกี่ยวข้องกับวิธีที่ Python นำสตริงจากrequestวัตถุของฉัน
Pat Jones

11
  • "\ r" => ส่งคืน
  • "\ n" => บรรทัดใหม่หรือ Linefeed (ซีแมนทิกส์)

  • ระบบที่ใช้ Unix ใช้เพียง "\ n" เพื่อวางบรรทัดข้อความ

  • Dos ใช้ "\ r \ n" เพื่อวางบรรทัดข้อความ
  • เครื่องอื่น ๆ ใช้เพียง "\ r" (พลเรือจัตวา, Apple II, Mac OS ก่อน OS X ฯลฯ )

5

\r ใช้เพื่อชี้ไปที่จุดเริ่มต้นของบรรทัดและสามารถแทนที่ข้อความจากที่นั่นเช่น

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

สร้างเอาต์พุตนี้:

hai

\n สำหรับบรรทัดใหม่


4

ในระยะสั้น \ r มีค่า ASCII 13 (CR) และ \ n มีค่า ASCII 10 (LF) Mac ใช้ CR เป็นตัวคั่นบรรทัด (อย่างน้อยก็เคยทำมาก่อนฉันไม่แน่ใจสำหรับ mac ที่ทันสมัย) * nix ใช้ LF และ Windows ใช้ทั้งสอง (CRLF)


1
ระบบ Mac OS X ใช้ LF เป็นค่าเริ่มต้น (เนื่องจากใช้ระบบ BSD Unix)
dreamlax

3

นอกจากคำตอบของ @Jon Skeet:

ตามเนื้อผ้า Windows ได้ใช้ \ r \ n, Unix \ n และ Mac \ r อย่างไรก็ตาม Mac รุ่นใหม่ใช้ \ n เนื่องจากใช้เป็น unix



2

\ r คือการรับคืนของสายการบิน; \ n เป็น New Line (Line Feed) ... ขึ้นอยู่กับระบบปฏิบัติการว่าแต่ละวิธีหมายถึงอะไร อ่านบทความนี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับความแตกต่างระหว่าง '\ n' และ '\ r \ n' ... ใน C.


1

ใช้เพื่อรับคืนรถ (ค่า ASCII คือ 13) \ n ใช้สำหรับบรรทัดใหม่ (ค่า ASCII คือ 10)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.