0

I have a bit of a weird question here at hands. I have a text that's encoded in such a way that each character is replaced by another character and I'm creating an application that will replace each character with a correct one. But I've come across a problem that I have trouble solving. Let me show with an example:

Original text: This is a line.
Encoded text:  (.T#*T#*%*=T50;

Now, as I said, each character represents another character, '(' is 'T', '.' is actually a 'h' and so on.

Now I could just go with

string decoded = encoded.Replace('(','T'); //T.T#*T#*%*=T50;

And that will solve one problem, but when I reach character 'T' that is actually encoded character 'i' I will have to replace all 'T' with 'i', which means that all previously decoded letter 'T's (that were once '(') will also change along with the encoded 'T'.

//T.T#*T#*%*=T50; -> i.i#*i#*%*=i50;

in this situation it's obvious that I should've just went the other way around, first change 'T' to 'i' and then '(' to 'T', but in the text I'm changing that kind of analysis is not an option.

What's the alternative here that I could do to perform the task correctly?

Thank you!

rafaelc
  • 57,686
  • 15
  • 58
  • 82
DethoRhyne
  • 930
  • 1
  • 9
  • 29
  • 1
    Using a million nested `string.Replace` statements will be horribly inefficient. Please could you expand on the encryption algorithm? If it's simply modifying the ASCII value according to some function then you'd be better off enumerating through your string as a char array. – Chris Pickford Jan 31 '17 at 13:39
  • You can even use a regular expression `.replace` to accomplish this. Follow this link http://stackoverflow.com/questions/7351031/regex-replace-multiple-groups – Hemi81 Jan 31 '17 at 13:43

3 Answers3

2

One possible solution is do not use replace string method at all.

Instead you can create method which for every encoded character will output decoded one, and then go through your string as through array of char and for every character in this array use "decryption" method to get decoded character - thus you'll receive decoded string.

For example (using StringBulder to create new string):

private static char Decode(char source)
{
        if (source == '(')
            return 'T';
        else if (source == '.')
            return 'h';
        //.... and so on
}

string source = "ABC";

var builder = new StringBuilder();
foreach (var c in source)
    builder.Append(Decode(c));

var result = builder.ToString();
Andrey Korneyev
  • 26,353
  • 15
  • 70
  • 71
  • Using a `switch` statement instead of a chain of `if/else if` would be more efficient in this instance. See http://stackoverflow.com/a/395965/2835541 – Chris Pickford Jan 31 '17 at 13:58
1

Using .Replace() probably isn't the way to go in the first place, since as you're finding it covers the whole string every time. And once you've modified the whole string once, the encoding is lost.

Instead, loop over the string one time and replace characters individually.

Create a function that accepts a char and returns the replaced char. For simplicity, I'll just show the signature:

private char Decode(char c);

Then just loop over the string and call that function on each character. LINQ can make short work of that:

var decodedString = new string(encodedString.Select(c => Decode(c)).ToArray());

(This is freehand and untested, you may or may not need that .ToArray() for the string constructor to be happy, I'm not certain. But you get the idea.)

If it's easier to read you can also just loop manually over the string and perhaps use a StringBuilder with each successive char to build the final decoded result.

David
  • 208,112
  • 36
  • 198
  • 279
  • Hmm, you and Andy pritty much gave the same answer, which works if I know all of the characters ahead of time, but the problem is that I don't.. Original text actually has glyphs changed so that character * looks like a blank space, etc. so I have to go letter by letter and keeping track of it programatically is bit of an issue. – DethoRhyne Jan 31 '17 at 14:02
  • However, I did think of an idea to convert the input string into a char array and then create a Dictionary> that will have the "encoded character" as a key and a list of indexes where those characters appear in the input string (or at that point, char array) and instead of .Replace-ing the string, I check for the key character, and replace everything. and do it as much times as i need.. – DethoRhyne Jan 31 '17 at 14:03
  • http://i.imgur.com/x83wAju.jpg < example from the text. I copied the highlighted text and just pasted it in the find window.. This is how the text works. – DethoRhyne Jan 31 '17 at 14:05
  • 1
    @DethoRhyne this appoach looks less efficient than suggested by David (or me). It requires memory overhead for dictionary as well as multiple passes through char array - first time to populate dictionary and then several times more to perform replaces - just compare it to *single* pass through array – Andrey Korneyev Jan 31 '17 at 14:08
  • Note that `encodedString.Select(...)` produces an `IEnumberable` and there does not seem to be a `new string(...)` overload that can consume that. Fixable either by adding `.ToArray()`, or by using `string.Concat(...)` instead. – Peter B Jan 31 '17 at 14:10
  • @DethoRhyne: I guess it's not really clear to me how you're doing a direct substitution decode (which is all `string.Replace()` would have been able to do) if you "don't know all of the characters". Doesn't each character have an equivalent replacement character? – David Jan 31 '17 at 14:10
  • @PeterB: I wasn't sure about that, but I've updated the answer to reflect your comment. Thanks! – David Jan 31 '17 at 14:11
  • It does, You can see that from the example text on the image. all ' ' are encoded as '*', all 'i's are encoded as '('. As I go I can check what each character is, but again, making a 200 line long switch case or if else does not seem like an optimal solution – DethoRhyne Jan 31 '17 at 14:16
  • 1
    @DethoRhyne: How you encapsulate the replacement of characters within that method is another matter, really. You can use a `switch`, or a series of `if/else` conditions, or perhaps a `Dictionary`, etc. The point of the question/answer is how to apply the replacement to a string such that you're not modifying the string mid-decode and breaking the decoding. Looping through the string one character at a time is how you'd do that. – David Jan 31 '17 at 14:19
0

Without knowledge of your encryption algorithm, this answer assumes that it's a simple character translation akin to the Caesar Cipher.

Pass in your encrypted string, the method loops over each character, adjusting it by the value of shiftDelta and returns the resulting string.

private string Decrypt(string input)
{
    const int shiftDelta = 10;

    var inputChars = input.ToCharArray();
    var outputChars = new char[inputChars.Length];

    for (var i = 0; i < outputChars.Length; i++)
    {
        // Perform character translation here
        outputChars[i] = (char)(inputChars[i] + shiftDelta); 
    }

    return outputChars.ToString();
}
Chris Pickford
  • 8,642
  • 5
  • 42
  • 73
  • I thought this might be how this was done, but it's not, I already checked that. It really does look like the characters were shifted/selected randomly to represent another characters. – DethoRhyne Jan 31 '17 at 14:14
  • If indeed the characters have been replaced randomly, how do you expect to decrypt it? – Chris Pickford Jan 31 '17 at 14:20
  • because, as I already said. The issue here is not that the letters themselves are "encrypted" but it's the glyphs that are changed. glyph for '*' is blank space, so I know that all '*' are supposed to be ' ', etc. – DethoRhyne Jan 31 '17 at 14:37