views:

177

answers:

6

I have a completed string like this

N:Pay in Cash++RGI:40++R:200++T:Purchase++IP:N++IS:N++PD:PC++UCP:598.80++UPP:0.00++TCP:598.80++TPP:0.00++QE:1++QS:1++CPC:USD++PPC:Points++D:Y++E:Y++IFE:Y++AD:Y++IR:++MV:++CP:~~ N:ERedemption++RGI:42++R:200++T:Purchase++IP:N++IS:N++PD:PC++UCP:598.80++UPP:0.00++TCP:598.80++TPP:0.00++QE:1++QS:1++CPC:USD++PPC:Points++D:Y++E:Y++IFE:Y++AD:Y++IR:++MV:++CP:

this string is like this

  1. It's list of PO's(Payment Options) which are separated by ~~
  2. this list may contains one or more OP
  3. PO contains only Key-Value Pairs which separated by :
  4. spaces are denoted by ++

I need to extract the values for Key "RGI" and "N".

I can do it via for loop , I want a efficient way to do this. any help on this.

Edit: from ~ ~ To ~~

+2  A: 

I think you should try a regular expression. Since you are using C#, check out this handy .NET RegEx cheat sheet.

mgroves
+1 - Nice link thanks.
Kyle Rozendo
A: 

Use string.Split() on ":" to extract the key-value pairs.

Then extract as you need them. If the positions in the string are not fixed,you will need to search each item in the resulting string[] array for a particular key.

If you need to search often, I would consider splitting the key-value pairs and placing in some sort of Dictionary.

Mitch Wheat
+1  A: 

hear ya go I used regular expressions and for a reasonable amount of text they preform well.

 static void Main(string[] args)
{
    string str = @"N:Pay in Cash++RGI:40++R:200++T:Purchase++IP:N++IS:N++PD:PC++UCP:598.80++UPP:0.00++TCP:598.80++TPP:0.00++QE:1++QS:1++CPC:USD++PPC:Points++D:Y++E:Y++IFE:Y++AD:Y++IR:++MV:++CP:~ ~N:ERedemption++RGI:42++R:200++T:Purchase++IP:N++IS:N++PD:PC++UCP:598.80++UPP:0.00++TCP:598.80++TPP:0.00++QE:1++QS:1++CPC:USD++PPC:Points++D:Y++E:Y++IFE:Y++AD:Y++IR:++MV:++CP:"; 
    System.Text.RegularExpressions.MatchCollection MC = System.Text.RegularExpressions.Regex.Matches(str,@"((RGI|N):.*?)\+\+");
    foreach( Match Foundmatch in MC)
    {
        string[] s = Foundmatch.Groups[1].Value.Split(':');
        Console.WriteLine("Key {0} Value {1} " ,s[0],s[1]);

    }

}
rerun
+2  A: 

You could parse the string into a dictionary and then pull in your values...

string s = "N:Pay in Cash++RGI:40++R:200++";

// Replace "++" with ","
s.Replace("++",",");

// Divide all pairs (remove empty strings)
string[] tokens = s.Split(new char[] { ':', ',' }, StringSplitOptions.RemoveEmptyEntries);

Dictionary<string, string> d = new Dictionary<string, string>();

for (int i = 0; i < tokens.Length; i += 2)
{
    string key = tokens[i];
    string value = tokens[i + 1];

    d.Add(key,value);
}
Zachary
+1 Even though the OP asked for a loop-less solution, this is [1] very easy to understand [2] still works when the boss says "and can you also grab the UCP value while you're in there"?
egrunin
+1  A: 

Here is an attempt doing a search based on index: (I prefer my LINQ solution that I added)

string test = "N:Pay in Cash++RGI:40++R:200++T:Purchase++IP:N++IS:N++PD:PC++UCP:598.80++UPP:0.00++TCP:598.80++TPP:0.00++QE:1++QS:1++CPC:USD++PPC:Points++D:Y++E:Y++IFE:Y++AD:Y++IR:++MV:++CP:~ ~N:ERedemption++RGI:42++R:200++T:Purchase++IP:N++IS:N++PD:PC++UCP:598.80++UPP:0.00++TCP:598.80++TPP:0.00++QE:1++QS:1++CPC:USD++PPC:Points++D:Y++E:Y++IFE:Y++AD:Y++IR:++MV:++CP:";
string[] parts = test.Split(new string[] { "~ ~" }, StringSplitOptions.None);            
var result = parts.Select(p => new
{
    N = p.Substring(p.IndexOf("N:") + 2,
        p.IndexOf("++") - (p.IndexOf("N:") + 2)),
    RGI = p.Substring(p.IndexOf("RGI:") + 4,
        p.IndexOf("++", p.IndexOf("RGI:")) - (p.IndexOf("RGI:") + 4))
});

Creates a list of two objects with following values:

result = {{N = "Pay in Cash", RDI = 40}, {N = "ERedemption", RDI = 42}}

EDIT: SOLUTION USING LINQ

I decided to try and do it all with LINQ and here is what I came up with:

string test = "N:Pay in Cash++RGI:40++R:200++T:Purchase++IP:N++IS:N++PD:PC++UCP:598.80++UPP:0.00++TCP:598.80++TPP:0.00++QE:1++QS:1++CPC:USD++PPC:Points++D:Y++E:Y++IFE:Y++AD:Y++IR:++MV:++CP:~ ~N:ERedemption++RGI:42++R:200++T:Purchase++IP:N++IS:N++PD:PC++UCP:598.80++UPP:0.00++TCP:598.80++TPP:0.00++QE:1++QS:1++CPC:USD++PPC:Points++D:Y++E:Y++IFE:Y++AD:Y++IR:++MV:++CP:";

 var result = test.Split(new string[] { "~ ~" }, StringSplitOptions.None).
     Select(m => m.Split(new string[] { "++" }, StringSplitOptions.None)).
     Select(p => p.Select(i => i.Split(':')).
         Where(o => o[0].Equals("N") || o[0].Equals("RGI")).
         Select(r => new { Key = r[0], Value = r[1]}));

It produces and array for each item that contains a Key Value pair of only N and RGI.

result = {{{Key = "N", Value = "Pay in Cash"}, {Key = "RDI", Value = 40}},
          {{Key = "N", Value = "ERedemption"}, {Key = "RDI", Value = 42}}}

If you want you can remove the Where and it will include all they Keys and their Values.

Kelsey
+3  A: 

Don't know if it's more efficient than RegEx, but here's a alternative using LINQ to Objects.

KeyValuePair<string, string>[] ns = (from po in pos.Split(new string[] { "~~" }, StringSplitOptions.RemoveEmptyEntries)
                                     from op in po.Split(new string[] { "++" }, StringSplitOptions.RemoveEmptyEntries)
                                     where op.StartsWith("N:") || op.StartsWith("RGI:")
                                     let op_split = op.Split(':')
                                     select new KeyValuePair<string, string>(op_split[0], op_split[1])).ToArray();
Franci Penov