วิธีที่ดีที่สุดในการแยกสตริงออกเป็นบรรทัด

คุณจะแยกสตริงหลายบรรทัดออกเป็นบรรทัดได้อย่างไร?

ฉันรู้อย่างนี้

var result = input.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

ดูน่าเกลียดเล็กน้อยและสูญเสียบรรทัดว่าง มีวิธีแก้ไขที่ดีกว่านี้หรือไม่?


person Konstantin Spirin    schedule 02.10.2009    source แหล่งที่มา
comment
เป็นไปได้ที่ซ้ำกันของ วิธีที่ง่ายที่สุดในการแบ่งสตริงในการขึ้นบรรทัดใหม่ .NET?   -  person Robin Bennett    schedule 13.05.2019


คำตอบ (9)


  • ถ้ามันดูน่าเกลียด เพียงลบการเรียก ToCharArray ที่ไม่จำเป็นออก

  • หากคุณต้องการแยกด้วย \n หรือ \r คุณมีสองตัวเลือก:

    • ใช้อาร์เรย์ตามตัวอักษร – แต่จะทำให้มีบรรทัดว่างสำหรับการลงท้ายบรรทัดแบบ Windows \r\n:

      var result = text.Split(new [] { '\r', '\n' });
      
    • ใช้นิพจน์ทั่วไป ตามที่ Bart ระบุ:

      var result = Regex.Split(text, "\r\n|\r|\n");
      
  • หากคุณต้องการเก็บบรรทัดว่าง ทำไมคุณถึงบอก C# ให้ทิ้งมันไปอย่างชัดเจน? (พารามิเตอร์ StringSplitOptions) – ใช้ StringSplitOptions.None แทน

person Konrad Rudolph    schedule 02.10.2009
comment
การลบ ToCharArray จะทำให้โค้ดเฉพาะแพลตฟอร์ม (NewLine สามารถเป็น '\n') - person Konstantin Spirin; 02.10.2009
comment
@Kon คุณควรใช้ Environment.NewLine หากนั่นคือข้อกังวลของคุณ หรือคุณหมายถึงที่มาของข้อความ มากกว่าสถานที่ประหารชีวิต? - person ; 20.01.2011
comment
@Will: หากคุณหมายถึงฉันแทนที่จะเป็น Konstantin: ฉันเชื่อ (อย่างยิ่ง) ว่าการแยกวิเคราะห์โค้ดควรพยายามทำงานบนทุกแพลตฟอร์ม (เช่น ควรอ่านไฟล์ข้อความที่เข้ารหัสด้วย บนแพลตฟอร์มแตกต่างจากแพลตฟอร์มที่ดำเนินการ) ดังนั้นสำหรับการแยกวิเคราะห์ Environment.NewLine จึงไม่ต้องไปไกลเท่าที่ฉันกังวล อันที่จริงแล้ว ในบรรดาโซลูชันที่เป็นไปได้ทั้งหมด ฉันชอบแบบที่ใช้นิพจน์ทั่วไปมากกว่า เนื่องจากมีเพียงโซลูชันเดียวที่จัดการแพลตฟอร์มต้นทางทั้งหมดได้อย่างถูกต้อง - person Konrad Rudolph; 20.01.2011
comment
ฮ่าๆ ไม่ได้สังเกตเห็นความคล้ายคลึงกันของชื่อ ฉันเห็นด้วยอย่างยิ่งในกรณีนี้ - person ; 20.01.2011
comment
@Hamish แค่ดูเอกสารของ enum หรือดูในคำถามดั้งเดิม! มันคือ StringSplitOptions.RemoveEmptyEntries - person Konrad Rudolph; 19.10.2011
comment
อ่า แย่แล้ว ฉันกำลังดู RegexOptions อยู่ ยังไม่ได้กินกาแฟของฉันเลย - person Hamish Grubijan; 19.10.2011
comment
แล้วข้อความที่มี '\r\n\r\n' ล่ะ string.Split จะส่งกลับ 4 บรรทัดว่าง แต่ด้วย '\r\n' ควรให้ 2 จะแย่กว่านั้นถ้า '\r\n' และ '\r' ผสมกันในไฟล์เดียว - person username; 27.04.2012
comment
@SurikovPavel ใช้นิพจน์ทั่วไป นั่นเป็นรูปแบบที่ต้องการอย่างแน่นอน เนื่องจากทำงานได้อย่างถูกต้องเมื่อใช้ร่วมกับการลงท้ายบรรทัดแบบใดก็ได้ - person Konrad Rudolph; 28.04.2012
comment
จุดเล็ก ๆ - ฉันมักจะใช้สตริงคำต่อคำในอาร์กิวเมนต์ที่สองถึง Regex.Split นั่นคือ - var result = Regex.Split(text, @"\r\n|\r|\n"); ในกรณีนี้มันทำงานด้วยวิธีใดวิธีหนึ่งเนื่องจากคอมไพเลอร์ C# ตีความ \n และ \r ในลักษณะเดียวกับที่ตัวแยกวิเคราะห์นิพจน์ทั่วไปทำ ในกรณีทั่วไปถึงแม้จะอาจทำให้เกิดปัญหาก็ตาม - person Ken Clement; 16.11.2017
comment
เพียงเพิ่มมูลค่า 2c ของฉัน เนื่องจาก OP ต้องการเก็บบรรทัดว่างไว้ คุณ ไม่สามารถ เขียน parser ที่เหมาะกับสภาพแวดล้อมทุกประเภท และ/หรือจัดการกรณีแบบผสม (เช่น RegEx) เพราะถ้าคุณมี '\n\ r' คุณรู้ได้อย่างไรว่ามันเป็น 'ตัวแบ่ง' หนึ่งตัวแทนที่จะเป็นสองตัวที่เพิ่งเข้ารหัสผิด? ถ้าเป็นอย่างหลังมันจะเป็นสองบรรทัดว่าง แต่ถ้าเป็นอย่างแรกเขาจะมีเพียงบรรทัดเดียวเท่านั้น คุณต้องถามว่าแหล่งที่มาของการเข้ารหัสคืออะไร หากแหล่งที่มาอยู่บนแพลตฟอร์มเดียวกันกับ parser (ไม่ว่าจะเป็นแพลตฟอร์มใดก็ตาม) คุณสามารถใช้ Environment.NewLine ตามที่ทราบแหล่งที่มาได้ - person Mark A. Donohoe; 20.08.2018
comment
@MarqueIV มีคำตอบที่เป็นไปได้ที่แตกต่างกันไปซึ่งทั้งหมดถูกต้อง ประการหนึ่งคือคาดหวังและต้องการไฟล์ข้อความสอดคล้องกัน อีกประการหนึ่งคือการไม่ยอมรับ "\r" เพียงอย่างเดียวเป็นตัวคั่นบรรทัด (เพราะว่า ยอมรับเถอะ ไม่มีระบบใดใช้แบบแผนนี้มานานกว่าทศวรรษ): แบบแผนที่ใช้จริงเพียงแบบเดียวคือ "\r\n" และ "\n" อันที่จริง ตัวอย่างของคุณ ("\n\r") ไม่เคย มีการขึ้นบรรทัดใหม่ที่ถูกต้องเลย อ่านว่ามีการขึ้นบรรทัดใหม่ สอง หรือมีข้อผิดพลาดเกิดขึ้น แต่อย่าถือเป็นการขึ้นบรรทัดเดียวอย่างแน่นอน - person Konrad Rudolph; 21.08.2018
comment
ก่อนอื่นข้อความของฉันพิมพ์ผิด ใช้ '\r\n' และประเด็นของฉันยังคงเหมือนเดิม: คุณไม่สามารถเขียนตัวแยกวิเคราะห์ สากล บนระบบได้ หากคุณจำเป็นต้องเว้นบรรทัดว่างไว้ โปรดทราบว่าด้วยการเพิ่มข้อจำกัดที่คุณจะไม่ยอมรับ '\r' เพียงอย่างเดียว และคุณต้องการใช้ '\n' เพื่อตรวจหาบรรทัดใหม่เท่านั้น ด้วยการเปลี่ยนแปลงนั้น คุณจะไม่มีตัวแยกวิเคราะห์สากลอีกต่อไป< /i> พิสูจน์ประเด็นของฉันโดยพื้นฐานแล้วว่าหากไม่มีข้อ จำกัด ดังกล่าวก็ไม่สามารถทำได้ (ง่าย *) และไม่จำเป็นต้องมีโอกาสเกิดขึ้นตั้งแต่แรก (*มันสามารถเล่นกับการเรียงลำดับ RegEx ได้ แต่นั่นกลับทำให้ช้าลงมาก) - person Mark A. Donohoe; 21.08.2018
comment
@MarqueIV ฉันคิดว่าคุณอ่านความคิดเห็นของฉันผิด: เนื่องจาก "\r" ไม่เคยใช้เป็นตัวคั่น ดังนั้นคุณจึงสามารถเขียนตัวแยกวิเคราะห์สากลที่ยอมรับตัวคั่นที่ใช้จริงทั้งหมดได้อย่างง่ายดาย ทำได้โดยเพียงแค่แยกบน "\r\n|\n" ไม่จำเป็นต้องมีอะไรแฟนซีไปกว่านี้อีกแล้ว แต่ตามจริงแล้ว ในทางปฏิบัติไม่มีอะไรผิดปกติกับโค้ด regex ที่แสดงในคำตอบของฉัน และมันจะทำงานได้ดีกับไฟล์ที่ผสมผสานสไตล์การขึ้นบรรทัดใหม่ที่แตกต่างกัน รวมถึง "\r" ที่ล้าสมัยด้วย - person Konrad Rudolph; 21.08.2018
comment
หากคุณมีข้อมูลที่มีสไตล์ผสมผสานอย่างที่คุณพูด ไม่มีทางที่จะแยกความแตกต่างระหว่าง '\n\r' และ '\n' และ '\r' โดยไม่สันนิษฐานว่าจะไม่มีวันมี '\r' และ เมื่อคุณตั้งสมมติฐานนั้น คุณได้ลบเงื่อนไขที่ฉันเพิ่งพูดถึงไปซึ่งทำให้เกิดความคลุมเครือออกไป นอกจากนี้ คุณไม่สามารถคาดเดาได้อยู่ดี เนื่องจากมีระบบฮาร์ดแวร์แบบฝังจำนวนมากที่ใช้ '\r' นั่นเป็นเหตุผลที่เทอร์มินัลให้คุณเลือกสามทางเลือกในการขึ้นบรรทัดใหม่ คุณจำเป็นต้องรู้ว่าคุณกำลังป้อนข้อมูลอยู่ข้างหน้า ฉันเดาว่าเราจะต้องไม่เห็นด้วยและแต่ละคนใช้สิ่งที่เหมาะกับเรา - person Mark A. Donohoe; 21.08.2018
comment
@MarqueIV นั่นเป็นสาเหตุที่ความคิดเห็นก่อนหน้าของฉันบอกว่า "ในทางปฏิบัติ" มันใช้งานได้ คุณกำลังโต้เถียงกับกรณีที่ไม่น่าเป็นไปได้ ใช่ เห็นได้ชัดว่ากรณีดังกล่าวมีความคลุมเครือ แต่ฉันขอยืนยันว่ากรณีเหล่านั้นไม่เกี่ยวข้องเพียงพอที่จะสนใจ และความคลุมเครือเหล่านี้ก็ไม่สามารถแก้ไขได้โดยพื้นฐานอยู่แล้ว: ไม่ กลยุทธ์การแยกวิเคราะห์จะทำงานได้เนื่องจากความคลุมเครือนั้นอยู่ในข้อมูลนั้นเอง ไม่อยู่ในกระบวนการแยกวิเคราะห์ - person Konrad Rudolph; 21.08.2018
comment
แต่ฉันเชื่อว่าคุณเพิ่งชี้ประเด็นให้ฉัน นั่นเป็นเหตุผลว่าทำไมฉันถึงใช้ Environment.NewLine เป็นค่าเริ่มต้น และใช้เฉพาะบางอย่างเช่นโซลูชัน RegEx หากคุณเสี่ยงชีวิตนอกขอบเขตของสถานการณ์ที่มีแนวโน้มมากกว่า มันเกิดขึ้น แต่อย่างที่พวกเขาพูดกัน นักฆ่าเวลาขนาดยักษ์กำลังใช้วิธีแก้ปัญหาสำหรับสิ่งต่าง ๆ ที่อาจเกิดขึ้น แทนที่จะเป็นสิ่งต่าง ๆ ที่เกิดขึ้น แน่นอนว่าวางแผนสำหรับอนาคต (เช่น อย่าออกแบบตัวเองให้อยู่ในมุมที่คุณไม่สามารถเปลี่ยนแปลงได้ในภายหลัง) แต่อย่าใช้อนาคตจริงๆ จนกว่าคุณจะจำเป็นจริงๆ กล่าวอีกนัยหนึ่ง ฉันไม่คิดว่าจุดของเราอยู่ไกลขนาดนั้น - person Mark A. Donohoe; 21.08.2018
comment
@MarqueIV “นั่นคือเหตุผลว่าทำไมฉันถึงใช้ Environment.NewLine” — แต่นั่นคือสิ่งที่ แย่ที่สุด ที่คุณสามารถทำได้ เพราะตอนนี้คุณเริ่มทำลายไฟล์จริงจำนวนมาก ในขณะที่โซลูชันของฉันทำลายไฟล์ที่มีอยู่จริงประมาณศูนย์ ตรวจสอบจำนวนโปรแกรมแก้ไขข้อความสมัยใหม่ที่ใช้เฉพาะบรรทัดใหม่ของระบบในการขึ้นบรรทัดใหม่ (คำใบ้: ไม่มีเลย) - person Konrad Rudolph; 21.08.2018
comment
ไม่มีอะไรเสียหายหากคุณไม่เคยวางแผนที่จะได้รับสิ่งที่ไม่ตรงกับการเข้ารหัสของแพลตฟอร์มของคุณ หากคุณรู้สิ่งนั้น (เช่นเดียวกับที่คุณรู้ว่าอาจไม่เคยมี '\r') แสดงว่าคุณกำลังปรับผลลัพธ์ให้เหมาะสม โดยไม่เสียเวลาไปกับการทำงานผ่านกลไก RegEx ที่ไม่จำเป็นต้องเป็น ซึ่งสามารถฆ่าเวลาได้- แอปพลิเคชันที่สำคัญ หากคุณมีการเข้ารหัสหลายรายการ ให้ใช้ RegEx คุณไม่สามารถทำสากลได้ ฉันไม่คิดว่าเรากำลังโต้เถียงประเด็นเดียวกัน คุณได้ทำของคุณและฉันได้ทำอย่างอื่น เป็นรูปสัมผัสแต่ไม่ขัดแย้งกัน - person Mark A. Donohoe; 21.08.2018
comment
@MarqueIV ฉันมีปัญหาในการทำความเข้าใจกรณีการใช้งานของคุณโดยสุจริต: คุณไม่จำเป็นต้องไปไกลกว่าแพลตฟอร์มปัจจุบันของคุณเพื่อค้นหาไฟล์ข้อความที่ใช้รูปแบบการลงท้ายบรรทัดที่แตกต่างกัน ฉันรู้ข้อเท็จจริงว่าระบบปัจจุบันของฉันมีไฟล์ที่มีรูปแบบต่างกัน (ฉันแก้ไขไฟล์หนึ่งเมื่อวานนี้ และฉันรู้เฉพาะเกี่ยวกับการสิ้นสุดบรรทัดที่แยกจากกันเนื่องจาก diff ตั้งค่าสถานะไฟล์เหล่านั้น) นี่ไม่ใช่ "การวางแผนสำหรับอนาคต" แต่เป็นการสร้างโค้ดที่แข็งแกร่งสำหรับที่นี่และเดี๋ยวนี้ - person Konrad Rudolph; 21.08.2018
comment
นอกจากนี้ เมื่อย้อนกลับไป อาจมีคนแย้งว่าหากคุณ ทำ ต้องการบรรทัดว่าง แต่ ไม่ บังคับใช้มาตรฐานสำหรับการเข้ารหัสบรรทัด คุณก็แค่ถามถึงปัญหา ถึงอย่างไร. ท้ายที่สุด หากคุณข้ามบรรทัดว่าง คุณ สามารถ เขียน Universal Parser ซึ่งจะทำให้เธรด Convo ทั้งหมดนี้ล้าสมัย! :) - person Mark A. Donohoe; 21.08.2018
comment
และในกรณีของคุณ ฉันขอยืนยันว่า 'แพลตฟอร์ม' คือการที่คุณใช้เครื่องมือแก้ไขที่อาจมีการลงท้ายบรรทัดที่แตกต่างกัน ดังนั้นคุณจึงเข้าใจความแตกต่าง แต่หากคุณใช้รูปแบบที่รู้จัก เช่น จากระบบอื่น และไม่ใช่สิ่งที่แก้ไขด้วยตนเอง ก็ไม่จำเป็นต้องวางแผนสำหรับกรณีนั้น และคุณสามารถเพิ่มปริมาณการประมวลผลได้ด้วยการไม่ทำ ขอย้ำอีกครั้ง เราไม่ได้โต้แย้งประเด็นเดียวกัน! เวลาและสถานที่ หากคุณกำลังรับไฟล์ที่ผู้ใช้แก้ไขได้ ฉันเห็นด้วยกับคุณ 100% แต่ถ้าคุณรับไฟล์ที่ระบบสร้างขึ้นจากระบบที่รู้จักบนแพลตฟอร์มเดียวกัน ฉันขอยืนหยัดตามคำกล่าวดั้งเดิมของฉัน :) - person Mark A. Donohoe; 21.08.2018
comment
@MarqueIV ไม่ไม่มีอะไรเสียหาย ไฟล์มีจุดสิ้นสุดบรรทัดที่แตกต่างกัน (แต่สอดคล้องกันภายใน) เนื่องจากสร้างขึ้นโดยบุคคลอื่นบนแพลตฟอร์มที่แตกต่างกัน แต่พวกมันก็มาอยู่บนเครื่องของฉัน — และฉันต้องการเน้นย้ำว่าเรากำลังมากโต้เถียงในประเด็นเดียวกัน เพราะโดยพื้นฐานแล้วฉันไม่เข้าใจว่ากรณีการใช้งานของคุณอยู่ที่ไหน ฉันไม่เห็นว่าเมื่อใดจะมีประโยชน์มากขึ้นและสร้างปัญหาน้อยลงในการแบ่งการขึ้นบรรทัดใหม่แบบฮาร์ดโค้ดของแพลตฟอร์มแทนที่จะใช้ฮิวริสติกของฉัน ซึ่งฉัน (และคนอื่น ๆ อีกมากมายอย่างชัดเจน) พบว่าทำงานได้จริง 100% ไฟล์. - person Konrad Rudolph; 21.08.2018
comment
สร้างโดยผู้คนหลากหลายบนแพลตฟอร์มที่แตกต่างกัน นั่นเป็นกรณีการใช้งานที่แตกต่างจากที่พูดจากบริการบนเว็บซึ่งสามารถคาดเดาการสิ้นสุดบรรทัดได้และสอดคล้องกัน และหากระบบนั้นอยู่บนแพลตฟอร์มเดียวกัน คุณสามารถใช้ Environment.NewLine และบดขยี้ประสิทธิภาพของ RegEx ได้ อีกครั้งเวลาและสถานที่ ฉันวางแผนไว้ แต่อย่าใช้วิธีแก้ปัญหาสำหรับสิ่งต่างๆ จนกว่าจะเกิดขึ้น เช่นเดียวกับโค้ด ประสิทธิภาพของนักพัฒนาก็เพิ่มขึ้นเช่นกัน - person Mark A. Donohoe; 21.08.2018
comment
เพื่อหวังว่าจะเอาใจคุณ หากคุณกำลังบอกว่าคุณต้องการระบบที่ต้องตรวจจับบรรทัดว่าง และคุณกำลังรับไฟล์ที่สร้างขึ้นบนแพลตฟอร์มที่มีการลงท้ายบรรทัดที่แตกต่างกัน และคุณรับประกันว่าคุณจะไม่ได้รับ '\r' ด้วยตัวเองและ /หรือการสิ้นสุดบรรทัดของคุณจะสอดคล้องกันในไฟล์เดียวกัน (ซึ่งคุณไม่สามารถแก้ไขได้หากแก้ไขบนเครื่องที่มีการสิ้นสุดบรรทัดที่แตกต่างกันสองรายการและการสิ้นสุดบรรทัดทั้งหมดไม่ได้รับการอัปเดต) ฉันยอมรับ... regex ใช้งานได้ แต่ฉันกำลังบอกว่าถ้าคุณ ไม่สามารถ รับประกันได้ มันก็จะไม่เป็นเช่นนั้น เพราะคุณจะไม่สามารถแยกความแตกต่างระหว่าง '\n\r' และ '\n' และ '\ ร' ทำให้รู้สึก? - person Mark A. Donohoe; 21.08.2018
comment
ตามความเป็นจริง ไม่มีอะไร จะใช้ได้ผลในกรณีนั้น ไม่ใช่แค่ RegEx เนื่องจากไม่มีมาตรฐานสำหรับการลงท้ายบรรทัดบน parser ซึ่งนำฉันกลับไปยังจุดก่อนหน้าของฉัน หากคุณกำลังพูดว่าบรรทัดว่าง มีความสำคัญต่อคุณ ดังนั้นคุณต้องกำหนดสิ่งที่แสดงถึงบรรทัดว่าง ไม่เช่นนั้นคุณจะไม่สามารถตอบคำถามข้างต้นได้ (โดยไม่มีหลักประกันอื่นๆ เหล่านั้น) - person Mark A. Donohoe; 21.08.2018
comment
ความแม่นยำที่มากขึ้นอาจช่วยได้: ไม่สามารถเขียน parser เพื่อจัดการการรวมกันของทุกกรณีได้ RE ที่นี่จะจัดการการรวมกันของสองกรณีใด ๆ ในไฟล์เดียว - person Mic; 23.09.2018

อัปเดต: ดูที่นี่สำหรับโซลูชันทางเลือก/async


มันใช้งานได้ดีและเร็วกว่า Regex:

input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None)

สิ่งสำคัญคือต้องมี "\r\n" อยู่ในอาร์เรย์ก่อน เพื่อให้ถือเป็นตัวแบ่งบรรทัดเดียว ข้อมูลข้างต้นให้ผลลัพธ์เดียวกันกับโซลูชัน Regex อย่างใดอย่างหนึ่งเหล่านี้:

Regex.Split(input, "\r\n|\r|\n")

Regex.Split(input, "\r?\n|\r")

ยกเว้นว่า Regex จะช้ากว่าประมาณ 10 เท่า นี่คือการทดสอบของฉัน:

Action<Action> measure = (Action func) => {
    var start = DateTime.Now;
    for (int i = 0; i < 100000; i++) {
        func();
    }
    var duration = DateTime.Now - start;
    Console.WriteLine(duration);
};

var input = "";
for (int i = 0; i < 100; i++)
{
    input += "1 \r2\r\n3\n4\n\r5 \r\n\r\n 6\r7\r 8\r\n";
}

measure(() =>
    input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None)
);

measure(() =>
    Regex.Split(input, "\r\n|\r|\n")
);

measure(() =>
    Regex.Split(input, "\r?\n|\r")
);

เอาต์พุต:

00:00:03.8527616

00:00:31.8017726

00:00:32.5557128

และนี่คือ วิธีการขยาย:

public static class StringExtensionMethods
{
    public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = false)
    {
        return str.Split(new[] { "\r\n", "\r", "\n" },
            removeEmptyLines ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None);
    }
}

การใช้งาน:

input.GetLines()      // keeps empty lines

input.GetLines(true)  // removes empty lines
person orad    schedule 08.08.2014
comment
โปรดเพิ่มรายละเอียดเพิ่มเติมเพื่อให้คำตอบของคุณมีประโยชน์มากขึ้นสำหรับผู้อ่าน - person Mohit Jain; 08.08.2014
comment
เสร็จแล้ว. เพิ่มการทดสอบเพื่อเปรียบเทียบประสิทธิภาพกับโซลูชัน Regex ด้วย - person orad; 08.08.2014
comment
รูปแบบค่อนข้างเร็วกว่าเนื่องจากการย้อนรอยน้อยลงด้วยฟังก์ชันการทำงานเดียวกันหากใช้ [\r\n]{1,2} - person ΩmegaMan; 27.02.2015
comment
@OmegaMan ที่มีพฤติกรรมที่แตกต่างกัน มันจะจับคู่ \n\r หรือ \n\n เป็นการขึ้นบรรทัดใหม่ซึ่งไม่ถูกต้อง - person orad; 28.02.2015
comment
@orad ฉันจะไม่โต้เถียงกับคุณ แต่ถ้าข้อมูลมีการป้อนบรรทัดในหลายตัวเลข ... มีแนวโน้มว่าจะมีบางอย่างผิดปกติกับข้อมูล ให้เราเรียกมันว่ากรณีขอบ - person ΩmegaMan; 28.02.2015
comment
@OmegaMan Hello\n\nworld\n\n เป็นเคสขอบได้อย่างไร? เห็นได้ชัดว่าเป็นหนึ่งบรรทัดพร้อมข้อความ ตามด้วยบรรทัดว่าง ตามด้วยอีกบรรทัดพร้อมข้อความ ตามด้วยบรรทัดว่าง - person Brandin; 09.08.2015

คุณสามารถใช้ Regex.Split:

string[] tokens = Regex.Split(input, @"\r?\n|\r");

แก้ไข: เพิ่ม |\r ในบัญชีสำหรับตัวยุติบรรทัด Mac (เก่ากว่า)

person Bart Kiers    schedule 02.10.2009
comment
สิ่งนี้ใช้ไม่ได้กับไฟล์ข้อความสไตล์ OS X เนื่องจากไฟล์เหล่านี้ใช้เพียง \r เป็นจุดสิ้นสุดบรรทัด - person Konrad Rudolph; 02.10.2009
comment
@Konrad Rudolph: AFAIK, '\r' ถูกใช้บนระบบ MacOS ที่เก่ามากและแทบไม่เคยพบเห็นอีกต่อไป แต่ถ้า OP จำเป็นต้องคำนึงถึงมัน (หรือถ้าฉันเข้าใจผิด) ก็สามารถขยาย regex ไปสู่บัญชีได้อย่างง่ายดาย: \r?\n|\r - person Bart Kiers; 02.10.2009
comment
@Bart: ฉันไม่คิดว่าคุณผิด แต่ฉัน ได้ พบการลงท้ายบรรทัดที่เป็นไปได้ซ้ำแล้วซ้ำเล่าในอาชีพของฉันในฐานะโปรแกรมเมอร์ - person Konrad Rudolph; 02.10.2009
comment
@ Konrad คุณอาจจะพูดถูก ฉันเดาว่าปลอดภัยดีกว่าขออภัย - person Bart Kiers; 02.10.2009
comment
ย้อนรอยน้อยลงและมีฟังก์ชันการทำงานเหมือนกันกับ [\r\n]{1,2} - person ΩmegaMan; 27.02.2015
comment
@ΩmegaMan: นั่นจะสูญเสียบรรทัดว่างเช่น \n\n. - person Mike Rosoft; 21.03.2019

หากคุณต้องการเก็บบรรทัดว่างไว้ ให้ลบ StringSplitOptions ออก

var result = input.Split(System.Environment.NewLine.ToCharArray());
person Jonas Elfström    schedule 02.10.2009
comment
NewLine สามารถเป็น '\n' และข้อความที่ป้อนสามารถมี \n\r - person Konstantin Spirin; 02.10.2009

ฉันมีคำตอบอื่นนี้ แต่คำตอบนี้อ้างอิงจากตอบ เร็วกว่ามาก เนื่องจากทำงานแบบอะซิงโครนัส แม้ว่าจะช้ากว่าเล็กน้อยก็ตาม

public static class StringExtensionMethods
{
    public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = false)
    {
        using (var sr = new StringReader(str))
        {
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                if (removeEmptyLines && String.IsNullOrWhiteSpace(line))
                {
                    continue;
                }
                yield return line;
            }
        }
    }
}

การใช้งาน:

input.GetLines()      // keeps empty lines

input.GetLines(true)  // removes empty lines

ทดสอบ:

Action<Action> measure = (Action func) =>
{
    var start = DateTime.Now;
    for (int i = 0; i < 100000; i++)
    {
        func();
    }
    var duration = DateTime.Now - start;
    Console.WriteLine(duration);
};

var input = "";
for (int i = 0; i < 100; i++)
{
    input += "1 \r2\r\n3\n4\n\r5 \r\n\r\n 6\r7\r 8\r\n";
}

measure(() =>
    input.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
);

measure(() =>
    input.GetLines()
);

measure(() =>
    input.GetLines().ToList()
);

เอาต์พุต:

00:00:03.9603894

00:00:00.0029996

00:00:04.8221971

person orad    schedule 16.12.2016
comment
ฉันสงสัยว่าเป็นเพราะคุณไม่ได้ตรวจสอบผลลัพธ์ของการแจงนับจริง ๆ หรือไม่ และดังนั้นจึงไม่ได้รับการดำเนินการ น่าเสียดายที่ฉันขี้เกียจเกินไปที่จะตรวจสอบ - person James Holwell; 19.10.2017
comment
ใช่แล้ว มันคือเรื่องจริง!! เมื่อคุณเพิ่ม .ToList() ให้กับทั้งสองสาย โซลูชัน StringReader จะช้าลงจริง ๆ ! บนเครื่องของฉันคือ 6.74 วินาทีเทียบกับ 5.10 วินาที - person JCH2k; 02.11.2017
comment
นั่นสมเหตุสมผลแล้ว ฉันยังคงชอบวิธีนี้มากกว่าเพราะมันช่วยให้ฉันได้รับบรรทัดแบบอะซิงโครนัส - person orad; 06.11.2017
comment
บางทีคุณควรลบส่วนหัวของโซลูชันที่ดีกว่าในคำตอบอื่น ๆ ของคุณและแก้ไขอันนี้... - person JCH2k; 06.11.2017

บิดเบี้ยวเล็กน้อย แต่เป็นบล็อกตัววนซ้ำที่ต้องทำ:

public static IEnumerable<string> Lines(this string Text)
{
    int cIndex = 0;
    int nIndex;
    while ((nIndex = Text.IndexOf(Environment.NewLine, cIndex + 1)) != -1)
    {
        int sIndex = (cIndex == 0 ? 0 : cIndex + 1);
        yield return Text.Substring(sIndex, nIndex - sIndex);
        cIndex = nIndex;
    }
    yield return Text.Substring(cIndex + 1);
}

จากนั้นคุณสามารถโทร:

var result = input.Lines().ToArray();
person JDunkerley    schedule 02.10.2009

เป็นเรื่องยากที่จะจัดการกับการลงท้ายบรรทัด ผสม อย่างถูกต้อง ดังที่เราทราบ อักขระการสิ้นสุดบรรทัดอาจเป็น "Line Feed" (ASCII 10, \n, \x0A, \u000A), "Carriage Return" (ASCII 13, \r, \x0D, \u000D) หรือบางส่วนผสมกัน ย้อนกลับไปที่ DOS Windows จะใช้ลำดับอักขระสองตัว CR-LF \u000D\u000A ดังนั้นชุดค่าผสมนี้ควรปล่อยบรรทัดเดียวเท่านั้น Unix ใช้ \u000A ตัวเดียว ส่วน Mac รุ่นเก่าๆ ใช้อักขระ \u000D ตัวเดียว วิธีมาตรฐานในการจัดการกับการผสมผสานของอักขระเหล่านี้ภายในไฟล์ข้อความเดียวมีดังนี้:

  • อักขระ CR หรือ LF แต่ละตัวควรข้ามไปยังบรรทัดถัดไป ยกเว้น...
  • ...หาก CR ตามด้วย LF (\u000D\u000A) ทันที ทั้งสองร่วมกันจะข้ามเพียงบรรทัดเดียว
  • String.Empty เป็นอินพุตเดียวที่ไม่ส่งคืนบรรทัด (อักขระใดๆ มีอย่างน้อยหนึ่งบรรทัด)
  • ต้องส่งคืนบรรทัดสุดท้ายแม้ว่าจะไม่มีทั้ง CR หรือ LF ก็ตาม

กฎก่อนหน้านี้อธิบายลักษณะการทำงานของ StringReader.ReadLine และฟังก์ชันที่เกี่ยวข้อง และฟังก์ชันที่แสดงด้านล่างนี้ให้ผลลัพธ์ที่เหมือนกัน เป็นฟังก์ชันการแบ่งบรรทัด C# ที่มีประสิทธิภาพ ซึ่งนำหลักเกณฑ์เหล่านี้ไปใช้อย่างถูกต้องเพื่อจัดการกับลำดับที่กำหนดเองหรือการรวมกันของ CR/LF อย่างถูกต้อง บรรทัดที่แจงนับไม่มีอักขระ CR/LF ใดๆ บรรทัดว่างจะถูกรักษาและส่งกลับเป็น String.Empty

/// <summary>
/// Enumerates the text lines from the string.
///   ⁃ Mixed CR-LF scenarios are handled correctly
///   ⁃ String.Empty is returned for each empty line
///   ⁃ No returned string ever contains CR or LF
/// </summary>
public static IEnumerable<String> Lines(this String s)
{
    int j = 0, c, i;
    char ch;
    if ((c = s.Length) > 0)
        do
        {
            for (i = j; (ch = s[j]) != '\r' && ch != '\n' && ++j < c;)
                ;

            yield return s.Substring(i, j - i);
        }
        while (++j < c && (ch != '\r' || s[j] != '\n' || ++j < c));
}

หมายเหตุ: หากคุณไม่สนใจค่าใช้จ่ายในการสร้างอินสแตนซ์ StringReader ในการเรียกแต่ละครั้ง คุณสามารถใช้โค้ด C# 7 ต่อไปนี้แทนได้ ตามที่ระบุไว้ แม้ว่าตัวอย่างข้างต้นอาจมีประสิทธิภาพมากกว่าเล็กน้อย แต่ฟังก์ชันทั้งสองนี้ให้ผลลัพธ์ที่เหมือนกันทุกประการ

public static IEnumerable<String> Lines(this String s)
{
    using (var tr = new StringReader(s))
        while (tr.ReadLine() is String L)
            yield return L;
}
person Glenn Slayden    schedule 06.02.2019

แยกสตริงออกเป็นบรรทัดโดยไม่มีการจัดสรรใดๆ

public static LineEnumerator GetLines(this string text) {
    return new LineEnumerator( text.AsSpan() );
}

internal ref struct LineEnumerator {

    private ReadOnlySpan<char> Text { get; set; }
    public ReadOnlySpan<char> Current { get; private set; }

    public LineEnumerator(ReadOnlySpan<char> text) {
        Text = text;
        Current = default;
    }

    public LineEnumerator GetEnumerator() {
        return this;
    }

    public bool MoveNext() {
        if (Text.IsEmpty) return false;

        var index = Text.IndexOf( '\n' ); // \r\n or \n
        if (index != -1) {
            Current = Text.Slice( 0, index + 1 );
            Text = Text.Slice( index + 1 );
            return true;
        } else {
            Current = Text;
            Text = ReadOnlySpan<char>.Empty;
            return true;
        }
    }


}
person Denis535    schedule 30.01.2021
comment
น่าสนใจ! มันควรจะใช้ IEnumerable<> หรือไม่? - person Konstantin Spirin; 01.02.2021

person    schedule
comment
นี่เป็นแนวทางที่สะอาดที่สุดในความเห็นส่วนตัวของฉัน - person primo; 21.10.2013
comment
มีความคิดเห็นใดในแง่ของประสิทธิภาพ (เทียบกับ string.Split หรือ Regex.Split) - person Uwe Keim; 25.01.2019