Peter
Peter

Reputation: 14518

Replace a list of characters in a string and do not override replaced characters

I'm working on this decryption program for a hobby of mine: geocaching.

The idea

I have a base list of chars :

[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,0,1,2,3,4,5,6,7,8,9]

And in a windows form you can specify with which character each character should be replaced.

[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,9,8,7,6,5,4,3,2,1,0]

So this would result in my string to decrypt being converted into uppercase.

example: the quick brown fox jumps over the lazy dog would result in THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG

How I solved it

public static string DecodeWithKey(string source, string keyBase, string keyValue)
{
    StringBuilder sb = new StringBuilder(source);
    for (int i = 0; i < keyBase.Length; i++)
    {
        sb = sb.Replace(keyBase[i], keyValue[i]);
    }
    return sb.ToString();
}

Now this works fine for the above sample. But it completely fails when you start moving characters around.

The problem is in the order of things

So let's say this is my base again:

[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,0,1,2,3,4,5,6,7,8,9]

And now I'm using a bit more realistic values to be replaced:

[a,b,c,d,t,f,g,h,i,j,k,l,m,n,o,p,q,r,s,p,u,v,w,x,y,z,0,1,2,3,4,5,6,7,8,9]

Notice, I changed e with t and t with p.

The result: the quick brown fox jumps over the lazy dog becomes php quick brown fox jumps ovpr php lazy dog

As you can see in the it replaced it to tht and then to php. Which is obvious from my logic.

How can I prevent this? so that is shows pht and doesn't replace a character twice.

I hope I have explained it clearly.

Upvotes: 0

Views: 1150

Answers (2)

Serge Wautier
Serge Wautier

Reputation: 21888

Why don't you simply build the decoded string character by character rather than modifying a copy of the source in-place?

First, build a dictionary that matches each coded char to its decoded value

public static string DecodeWithKey(string source, Dictionary<char,char> decoder) 
{ 
    StringBuilder sb = new StringBuilder(source.Length); 
    for (int i = 0; i < source.Length; i++) 
    { 
        sb.Append( decoder[source[i]] ); // error management left out as an exercice
    } 
    return sb.ToString(); 
}

In response to Piotr comment, let's try to throw some LINQ into the game:

public static string DecodeWithKey(string source, Dictionary<char,char> decoder) 
{ 
    return String.Concat(from ch in source select decoder[ch]);
}

Upvotes: 3

Ray
Ray

Reputation: 46595

You can use regex replace to do what you want. Have a look at this question.

Convert your replacements to a dictionary, and then:

var regex = new Regex(String.Join("|",map.Keys));
var newStr = regex.Replace(str, m => map[m.Value]);

Upvotes: 1

Related Questions