1
\$\begingroup\$

Hello this is a Console App(.Net Core) in Visual Studio 2019 and i am trying to split a string into sentences and then add them into a dictionary with Key the first word of the sentence and Value the sentence itself. I have the following code and i wonder if the way i did it has of course a better way to handle it.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace StringParse
{
    class Program
    {
        static void Main(string[] args)
        {
            string phrase = @"MHD001|LOCCOD|GRCACS|20191117|133601|CB|trx_grcacs_tsk_20191117133601498|
TSK001|GLS|GRCACS|59144|59144|2|TU|93000161357|TRACE|INF|DE 800|please send us the completely address information-thanks|68481|20191117|133555|
TSA001|X|
TSI001|3655|please send us the completely address information-thanks|66510|
TSI001|5637|80337|61335|
TSI001|5841|DE|61313|
MTR001|5|";
            /////////////////////////////////////////////////////////////////////
            string sentenceSeparator = @"\b[A-Z]{3}\d{3}\b";
            string[] words = phrase.Split('|');

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < words.Length; i++)
            {
                //If current word array matches the regex
                if (words[i].Equals(sentenceSeparator))
                {
                    // If the current array value doesn't match, then continue the current line.
                    sb.Append(words[i]);
                    sb.Append(" ");
                }
                else
                {
                    if (i == 0)
                    {
                        // on the 1st iteration, we don't need a new line before the text value.
                        sb.Append(words[i]);
                        sb.Append(" ");
                    }
                    else
                    {
                        sb.Append(words[i]);
                        sb.Append(" ");
                    }
                }
            }
            string[] sentences = sb.ToString().Split('\r');

            ////////////////////////////////////////////////////////////////////////

            Regex regx = new Regex(sentenceSeparator);

            MatchCollection matches = Regex.
                Matches(phrase, sentenceSeparator,
                RegexOptions.Compiled |
                RegexOptions.CultureInvariant);

            for (int i = 1; i < matches.Count; ++i)
            {
                phrase = phrase
                    .Replace(matches[i].Value,
                    Environment.NewLine + matches[i].Value);
            }
            ///////////////////////////////////////////////////////////////////////////////

            Dictionary<Match, string> dic = matches.Zip(sentences, (x, y)
                 => new { Key = x, Value = y }).ToDictionary(x => x.Key, y => y.Value);

            foreach (KeyValuePair<Match, string> kvp in dic)
            {
                Console.WriteLine("Key = {0}" + Environment.NewLine + "Value = {1}", kvp.Key, kvp.Value);
            }

        }

    }

}

output will be like that:

Key = MHD001
Value = MHD001 LOCCOD GRCACS 20191117 133601 CB trx_grcacs_tsk_20191117133601498
Key = TSK001
Value = TSK001 GLS GRCACS 59144 59144 2 TU 93000161357 TRACE INF DE 800 please send us the completely address information-thanks 68481 20191117 133555
Key = TSA001
Value = TSA001 X
Key = TSI001
Value = TSI001 3655 please send us the completely address information-thanks 66510
Key = TSI001
Value = TSI001 5637 80337 61335
Key = TSI001
Value = TSI001 5841 DE 61313
Key = MTR001
Value = MTR001 5
\$\endgroup\$
16
  • 1
    \$\begingroup\$ Did you copy the code directly from your IDE? I am asking because in the first loop the whole if..else..if..else seems senseless because in each branch the code is doing the exactly same thing. \$\endgroup\$
    – Heslacher
    Commented Jan 2, 2020 at 15:09
  • \$\begingroup\$ Yes i did copy it from the IDE.. first i split the phrase into words. then with stringbuilder and the regex i made it like sentence, then i added to another array. I do not have experience with C# and thats why i wonder if this is ok \$\endgroup\$ Commented Jan 2, 2020 at 15:11
  • 2
    \$\begingroup\$ This code doesn't seem to work. It creates an error when compiling with Framework 4.8. MatchCollection doesn't contain a Zip method. \$\endgroup\$
    – user33306
    Commented Jan 2, 2020 at 16:31
  • 2
    \$\begingroup\$ Alright, while I don't have a windows at hand, I was able to verify the code as posted works when running it against dotnet core 3.0.100 when targeting netcoreapp3.0. As such I have reopened the question \$\endgroup\$
    – Vogel612
    Commented Jan 3, 2020 at 12:03
  • 1
    \$\begingroup\$ Just add Cast<Match>() and it works ``` Dictionary<Match, string> dic = matches.Cast<Match>().Zip(sentences, (x, y) => new { Key = x, Value = y }).ToDictionary(x => x.Key, y => y.Value); ``` \$\endgroup\$ Commented Jan 3, 2020 at 12:11

1 Answer 1

2
\$\begingroup\$

The whole if..else..if..else inside the first loop is senseless because each branch does exactly the same.


Using Split('|') and combining the resulting array with one space " " is the same like replacing | by a space.


The Regex regx = new Regex(sentenceSeparator); is superflous because you don't use regex at all.


The loop

for (int i = 1; i < matches.Count; ++i)
{
    phrase = phrase
        .Replace(matches[i].Value,
        Environment.NewLine + matches[i].Value);
}  

is superflous because you aren't using phrase afterwards.


As it seems (untested) you can use Zip() with a MatchCollection if you use .NET Core 3.0.100 but to make your code runnable without .NET Core you should change

Dictionary<Match, string> dic = matches.Zip(sentences, (x, y)
             => new { Key = x, Value = y }).ToDictionary(x => x.Key, y => y.Value);  

to

Dictionary<Match, string> dic = matches.Cast<Match>().Zip(sentences, (x, y)
             => new { Key = x, Value = y }).ToDictionary(x => x.Key, y => y.Value);

It comes for sure from copying the code (which seems to be posted using Shift + Enter for phrase) from this question to the IDE....if you inspect the result of dict you will see that from the second item on the Value is prepended by a \n. This can be prevented by using TrimStart('\n') on y at new { Key = x, Value = y }.


Implementing the mentioned points will lead to

   static void Main(string[] args)
    {
        string phrase = @"MHD001|LOCCOD|GRCACS|20191117|133601|CB|trx_grcacs_tsk_20191117133601498|TSK001|GLS|GRCACS|59144|59144|2|TU|93000161357|TRACE|INF|DE 800|please send us the completely address information-thanks|68481|20191117|133555|TSA001|X|TSI001|3655|please send us the completely address information-thanks|66510|TSI001|5637|80337|61335|TSI001|5841|DE|61313|MTR001|5|";

        string[] sentences = phrase.Replace('|',' ').Split('\r');
        string sentencePattern = @"\b[A-Z]{3}\d{3}\b";

        MatchCollection matches = Regex.
            Matches(phrase, sentencePattern,
            RegexOptions.Compiled |
            RegexOptions.CultureInvariant);

        Dictionary<Match, string> dic = matches.Cast<Match>().Zip(sentences, (x, y)
             => new { Key = x, Value = y.TrimStart('\n') }).ToDictionary(x => x.Key, y => y.Value);

        foreach (KeyValuePair<Match, string> kvp in dic)
        {
            Console.WriteLine("Key = {0}" + Environment.NewLine + "Value = {1}", kvp.Key, kvp.Value);
        }
    }
\$\endgroup\$
1
  • \$\begingroup\$ thank you for your valuable comments and the great review. \$\endgroup\$ Commented Jan 4, 2020 at 10:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.