লাইনে স্ট্রিং বিভক্ত করার সেরা উপায়


143

আপনি মাল্টি-লাইন স্ট্রিংগুলিকে লাইনে ভাগ করবেন কীভাবে?

আমি এইভাবে জানি

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

কিছুটা কুরুচিপূর্ণ দেখায় এবং খালি লাইন হারিয়ে যায়। এর চেয়ে ভাল সমাধান কি আছে?



1
আমি এই সমাধানটি পছন্দ করি, কীভাবে এটি আরও সহজ করা যায় তা আমি জানি না। দ্বিতীয় প্যারামিটার অবশ্যই শূন্যস্থান সরিয়ে দেয়।
নেপিংর্যাবিট

উত্তর:


172
  • যদি এটি কুৎসিত দেখাচ্ছে, কেবল অপ্রয়োজনীয় ToCharArrayকলটি সরিয়ে ফেলুন ।

  • আপনি হয় অনুসারে বিভক্ত করতে চান, \nবা \r, দুই বিকল্প আছে:

    • একটি অ্যারে আক্ষরিক ব্যবহার করুন - তবে এটি আপনাকে উইন্ডোজ-স্টাইলের লাইনের শেষের জন্য খালি লাইন দেয় \r\n:

      var result = text.Split(new [] { '\r', '\n' });
    • বার্ট দ্বারা নির্দেশিত হিসাবে একটি নিয়মিত অভিব্যক্তি ব্যবহার করুন:

      var result = Regex.Split(text, "\r\n|\r|\n");
  • আপনি যদি খালি লাইনগুলি সংরক্ষণ করতে চান, তবে আপনি কেন সি # কে এটিকে ফেলে দেওয়ার জন্য স্পষ্টভাবে বলছেন? ( StringSplitOptionsপরামিতি) - StringSplitOptions.Noneপরিবর্তে ব্যবহার করুন।


2
তোচারআরে সরানো কোড প্ল্যাটফর্ম-নির্দিষ্ট করে তুলবে (নিউলাইন '\ n' হতে পারে)
কনস্ট্যান্টিন স্পিরিন

1
@Will: চালু সুযোগ আপনি কনস্টানটিন পরিবর্তে আমাকে উল্লেখ করা হয়েছে বন্ধ: আমি বিশ্বাস করি ( দৃঢ়ভাবে ) যে পার্স কোড সব প্ল্যাটফর্মে কাজ প্রচেষ্টা করা উচিত (যেমন এটি পাঠ্য ফাইল যে এনকোড করা হয়েছে পড়া উচিত বিভিন্ন নির্বাহ প্ল্যাটফর্ম চেয়ে প্ল্যাটফর্মের )। পার্সিংয়ের জন্য, Environment.NewLineযতটা আমি উদ্বিগ্ন হ'ল না। প্রকৃতপক্ষে, সমস্ত সম্ভাব্য সমাধানগুলির মধ্যে আমি নিয়মিত এক্সপ্রেশন ব্যবহার করে এমনটিকে পছন্দ করি যেহেতু কেবলমাত্র সমস্ত উত্স প্ল্যাটফর্ম সঠিকভাবে পরিচালনা করে।
কনরাড রুডল্ফ

2
@ হামিশ ঠিক আছে শুধু এনামের ডকুমেন্টেশন দেখুন, বা মূল প্রশ্নটি দেখুন! এটা StringSplitOptions.RemoveEmptyEntries
কনরাড রুডল্ফ

8
'\ R \ n \ r \ n' থাকা পাঠ্য সম্পর্কে কীভাবে। স্ট্রিং.স্প্লিট 4 টি খালি লাইন ফিরিয়ে দেবে, তবে '\ r \ n' দিয়ে এটি দেওয়া উচিত 2. এটি আরও খারাপ হয় যদি '\ r \ n' এবং '\ r' এক ফাইলে মিশ্রিত হয়।
ইউজারনেম

1
সুরিকভপ্যাভেল এটি অবশ্যই পছন্দসই বৈকল্পিক, কারণ এটি লাইন শেষের কোনও সংমিশ্রণের সাথে সঠিকভাবে কাজ করে।
কনরাড রুডল্ফ

134
using (StringReader sr = new StringReader(text)) {
    string line;
    while ((line = sr.ReadLine()) != null) {
        // do something
    }
}

12
এটি আমার বিষয়গত মতামত, সবচেয়ে পরিষ্কার পদ্ধতির।
primo

5
পারফরম্যান্সের দিক থেকে কোনও ধারণা (তুলনা string.Splitবা এর সাথে Regex.Split)?
উওয়ে কেইম

52

আপডেট: বিকল্প / অ্যাসিঙ্ক সমাধানের জন্য এখানে দেখুন ।


এটি দুর্দান্ত কাজ করে এবং রেগেক্সের চেয়ে দ্রুত:

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

"\r\n"অ্যারেতে প্রথমে থাকা জরুরী যাতে এটি এক লাইনের বিরতি হিসাবে নেওয়া হয়। উপরেরগুলি এই রেজেক্স সমাধানগুলির উভয়ের মতোই ফলাফল দেয়:

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

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

রেজেক্স বাদে প্রায় 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

আপনার উত্তরটি পাঠকদের জন্য আরও কার্যকর করতে দয়া করে আরও কিছু বিশদ যুক্ত করুন।
মোহিত জৈন

সম্পন্ন. রেজেজ সমাধানের সাথে এর পারফরম্যান্সের তুলনা করতে একটি পরীক্ষাও যুক্ত করেছে।
ওড়াদ

যদি কেউ ব্যবহার করে তবে একই কার্যকারিতা সহ কম ব্যাকট্র্যাকিংয়ের কারণে কিছুটা দ্রুত প্যাটার্ন[\r\n]{1,2}
gaমেগামান

@ ওমেগামান এর কিছু আলাদা আচরণ আছে। এটি মিলবে \n\rবা \n\nএকক লাইন-ব্রেক হিসাবে যা সঠিক নয়।
ওরাড

3
@ ওমেগামন কীভাবে Hello\n\nworld\n\nপ্রান্তের কেস? এটি পাঠ্যের সাথে স্পষ্টভাবে একটি লাইন, তার পরে একটি খালি রেখা, তারপরে পাঠ্য সহ অন্য একটি লাইন, খালি রেখা পরে।
ব্র্যান্ডিন

36

আপনি Regex.Split ব্যবহার করতে পারেন:

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

সম্পাদনা: |\r(পুরানো) ম্যাক লাইন টার্মিনেটরগুলির অ্যাকাউন্টে যুক্ত করা হয়েছে ।


এটি যদিও ওএস এক্স স্টাইলের পাঠ্য ফাইলগুলিতে কাজ করবে না, কারণ এগুলি কেবল \rলাইন শেষ হিসাবে ব্যবহৃত হয় ।
কনরাড রুডল্ফ

2
@ কনরাদ রুডল্ফ: আফাইক, '\ r' খুব পুরানো ম্যাকওএস সিস্টেমে ব্যবহৃত হয়েছিল এবং এর আগে আর কখনও দেখা হয় নি। তবে যদি ওপিকে এটির হিসাবরক্ষণের প্রয়োজন হয় (বা যদি আমি ভুল করে থাকি), তবে অবশ্যই রেজিেক্সটি অবশ্যই অবশ্যই এটির অ্যাকাউন্টিংয়ের জন্য বাড়ানো যেতে পারে:? R? \ N |
K

@Bart: আমি তুমি ভুল মনে করি না কিন্তু আমি করেছি বারবার প্রোগ্রামার হিসেবে আমার কর্মজীবনের সব সম্ভব লাইন শেষা w শ সম্মুখীন হয়েছে।
কনরাড রুডলফ

@ কনরাড, আপনি সম্ভবত ঠিক বলেছেন। অনুমানের চেয়ে ভাল নিরাপদ, আমার ধারণা।
বার্ট কায়ার্স

1
@ GamegaMan: এটি খালি লাইনগুলি হারাবে, যেমন \ n \ n।
মাইক রোসফট

9

আপনি যদি খালি লাইন রাখতে চান তবে কেবল স্ট্রিংস্প্লিটঅ্যাপশনগুলি সরান।

var result = input.Split(System.Environment.NewLine.ToCharArray());

2
নিউলাইন '\ n' হতে পারে এবং ইনপুট পাঠ্যে "\ n \ r" থাকতে পারে।
কনস্ট্যান্টিন স্পিরিন 9

4

আমি এই ছিল অন্যান্য উত্তর কিন্তু এই এক, জ্যাক এর উপর ভিত্তি করে উত্তর , উল্লেখযোগ্যভাবে দ্রুততর পছন্দের করা যেতে পারে যেহেতু এটি দ্বারা অ্যাসিঙ্ক্রোনাস কাজ করে, যদিও কিছুটা মন্থর।

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


আমি অবাক হচ্ছি কারণ এটি হ'ল কারণ আপনি প্রকৃতপক্ষে গণনার ফলাফলগুলি পরীক্ষা করছেন না এবং তাই এটি কার্যকর করা হচ্ছে না। দুর্ভাগ্যক্রমে, আমি চেক করতে খুব অলস।
জেমস হলওয়েল

হ্যাঁ, এটা আসলে !! আপনি যখন উভয় কলগুলিতে .ToList () যুক্ত করেন, তখন স্ট্রিংরেডার সমাধানটি স্লো হয়! আমার মেশিনে এটি 6.74s বনাম 5.10 এস
জেসিএইচ

এটা বোধগম্য. আমি এখনও এই পদ্ধতিটিকে পছন্দ করি কারণ এটি আমাকে অবিচ্ছিন্নভাবে লাইন পেতে দেয়।
ওড়াদ

হতে পারে আপনার অন্য উত্তরের "আরও ভাল সমাধান"
শিরোনামটি


2

কিছুটা বাঁকানো, তবে এটি করার জন্য একটি পুনরুদ্ধারকারী অবরুদ্ধ:

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();

1
    private string[] GetLines(string text)
    {

        List<string> lines = new List<string>();
        using (MemoryStream ms = new MemoryStream())
        {
            StreamWriter sw = new StreamWriter(ms);
            sw.Write(text);
            sw.Flush();

            ms.Position = 0;

            string line;

            using (StreamReader sr = new StreamReader(ms))
            {
                while ((line = sr.ReadLine()) != null)
                {
                    lines.Add(line);
                }
            }
            sw.Close();
        }



        return lines.ToArray();
    }

1

মিশ্র লাইনের সমাপ্তিগুলি সঠিকভাবে পরিচালনা করা কঠিন । আমরা জানি, লাইন পরিসমাপ্তি অক্ষরের হতে পারেন "লাইন ফিড" (হওয়া ASCII 10, \n, \x0A, \u000A), "গাড়ি ফেরত" (হওয়া ASCII 13, \r, \x0D, \u000D), অথবা তাদের কিছু সংমিশ্রণ। ডস-এ ফিরে গিয়ে উইন্ডোজ দ্বি-চরিত্রের ক্রম সিআর-এলএফ ব্যবহার করে \u000D\u000A, সুতরাং এই সংমিশ্রণটি কেবল একটি একক লাইন নির্গত করতে হবে। ইউনিক্স একটি একক ব্যবহার করে \u000Aএবং খুব পুরানো ম্যাকগুলি একটি একক \u000Dঅক্ষর ব্যবহার করে । একটি একক পাঠ্য ফাইলের মধ্যে এই অক্ষরগুলির স্বেচ্ছাসেবী মিশ্রণের চিকিত্সার মানক উপায়টি নিম্নরূপ:

  • প্রতিটি সিআর বা এলএফ অক্ষর পরের লাইনে ছাড়ি ...
  • ... যদি কোনও সিআর অবিলম্বে এলএফ ( \u000D\u000A) অনুসরণ করে তবে এই দুটি একসাথে কেবল একটি লাইন ছেড়ে যায়।
  • String.Empty একমাত্র ইনপুট যা কোনও লাইন দেয় না (কোনও অক্ষর কমপক্ষে একটি লাইন অন্তর্ভুক্ত করে)
  • সিআর বা এলএফ না থাকলেও শেষ লাইনটি অবশ্যই ফিরতে হবে।

পূর্ববর্তী নিয়মটি স্ট্রিংরেডার সম্পর্কিত আচরণ বর্ণনা করে e রিডলাইন এবং সম্পর্কিত ফাংশন, এবং নীচে প্রদর্শিত ফাংশনটি অভিন্ন ফলাফল প্রকাশ করে। এটি একটি দক্ষ সি # লাইন ব্রেকিং ফাংশন যা সিআর / এলএফের যেকোন স্বেচ্ছাসেবী ক্রম বা সংমিশ্রণটি সঠিকভাবে পরিচালনা করতে এই নির্দেশিকাগুলি যথাযথভাবে প্রয়োগ করে। গণিত রেখাগুলিতে কোনও সিআর / এলএফ অক্ষর থাকে না। খালি লাইন সংরক্ষণ করা হয় এবং হিসাবে ফিরে আসে 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প্রতিটি কলটিতে একটি উদাহরণ তৈরি করার ওভারহেডটিকে আপত্তি না করেন তবে পরিবর্তে আপনি নীচের সি # 7 কোডটি ব্যবহার করতে পারেন । যেমনটি উল্লেখ করা হয়েছে, উপরে উদাহরণটি আরও কিছুটা দক্ষ হতে পারে তবে এই দুটি ফাংশনই একই ফলাফল দেয় results

public static IEnumerable<String> Lines(this String s)
{
    using (var tr = new StringReader(s))
        while (tr.ReadLine() is String L)
            yield return L;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.