0

I want to replace characters in a string content in file. Below Dictionary shows the Key as unwanted character and i need to replace with the value in the Dictionary.

Dictionary<string, string> unwantedCharacters = new Dictionary<string, string>();
        unwantedCharacters["É"] = "@";
        unwantedCharacters["Ä"] = "[";
        unwantedCharacters["Ö"] = "\\";
        unwantedCharacters["Å"] = "]";
        unwantedCharacters["Ü"] = "^";
        unwantedCharacters["é"] = "`";
        unwantedCharacters["ä"] = "{";
        unwantedCharacters["ö"] = "|";
        unwantedCharacters["å"] = "}";
        unwantedCharacters["ü"] = "~";

Here is the code i currently using,Feel like its taking too much execution time..

 for (int index = 0; index < fileContents.Length; index++)
        {
            foreach (KeyValuePair<string, string> item in unwantedCharacters)
            {
                if (fileContents.IndexOf(item.Key) > -1)
                {
                    fileContents = fileContents.Replace(item.Key, item.Value); // Replacing straight characters
                }
            }
        }

ie,Looping in two levels.. Any other ways implement this..Any help will be appreciated

Jason Evans
  • 28,906
  • 14
  • 90
  • 154
Shiju Shaji
  • 1,682
  • 17
  • 24

6 Answers6

3

Since you're not modifying the length of the string, if you make unwantedCharacters a Dictionary<char, char> rather than <string, string>, you can do the following:

var charArray = fileContents.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
    char replacement;
    if (unwantedCharacters.TryGetValue(charArray[i], out replacement))
        charArray[i] = replacement;
}
fileContents = new string(charArray);

Performance is O(n) in releation to the length of the input string.

Rawling
  • 49,248
  • 7
  • 89
  • 127
  • +1 interesting solution. Never thought about converting file to array of chars. It would be interesting to compare performance of solutions with strings vs chars array – Sergey Berezovskiy Feb 22 '13 at 10:29
  • 1
    I think `fileContents` is already a string... just a string read from a file. Performance-wise I'd expect this to be on a par with the `StringBuilder` answer (since that has a fixed length supplied too) but faster than doing anything that involves concatenating or replacing in strings. – Rawling Feb 22 '13 at 10:41
2

It seems fileContents is a string value here. You could simply call replace on the string.

foreach (KeyValuePair<string, string> item in unwantedCharacters)
{
    fileContents = fileContents.Replace(item.Key, item.Value); 
}
Ravi Y
  • 4,296
  • 2
  • 27
  • 38
2

Look this answer: answer

But in this code put your characteres:

IDictionary<string,string> map = new Dictionary<string,string>()
    {
       {"É", = "@"},
       {"Ä", = "["},
       {"Ö", = "\\"},
       ...
    };
Community
  • 1
  • 1
user1848942
  • 355
  • 1
  • 5
  • 21
2

In order to replace many characters in string, consider to use StringBuilder Class. Replacing one character in string causes in creation of entirly new string so it is highly inefficient. Try the below:

var sb = new StringBuilder(fileContents.Length);

foreach (var c in fileContents)
    sb.Append(unwantedCharacters.ContainsKey(c) ? unwantedCharacters[c] : c);

fileContents = sb.ToString();

I assumed here, that your dictionary contains characters (Dictionary<char, char>). It it is a case, just comment and I will edit the solution.

I also assumed, that fileContents is a string.

You can also use LINQ instead of StringBuilder:

var fileContentsEnumerable = from c in fileContents
                             select unwantedCharacters.ContainsKey(c) ? unwantedCharacters[c] : c;

fileContents = new string(fileContentsEnumerable.ToArray());
Ryszard Dżegan
  • 24,366
  • 6
  • 38
  • 56
1

You want to build a filter. You process the contents of the file, and do the substitution while you process it.

Something like this:

        using(StreamReader reader = new StreamReader("filename"))
        using (StreamWriter writer = new StreamWriter("outfile"))
        {
            char currChar = 0;
            while ((currChar = reader.Read()) >= 0)
            {
                char outChar = unwantedCharacters.ContainsKey(currChar)
                                   ? unwantedCharacters[currChar]
                                   : (char) currChar;
                writer.Write(outChar);
            }
        }

You can use a memeory stream if your data is in memory, or a loop through fileContents is that's a string or char array.

This solution is O(n) where n is the length of the file, thanks to the dictionary (note that you could use a simple sparse array instead of the dictionary and you would gain quite a bit of speed).

Do not iterate through the dictionary as other suggest as each substitution is O(n) so you end up with a total time of O(n*d), d being the dictionary size, as you have to go through the file many times.

Mau
  • 14,234
  • 2
  • 31
  • 52
0

Remove the foreach and replace with a for loop from 0 to item.Count. This article will help, hopefully.

Community
  • 1
  • 1
Paul
  • 4,160
  • 3
  • 30
  • 56
  • @Downvoter: Why the down vote? Please explain. The user wanted speed, I suspect, at the price of readability, hence my post. – Paul Feb 22 '13 at 11:44