0

I'm having some issues with replacing words in a string with values from a dictionary. Here's a small sample of my current code:

Dictionary<string, string> replacements = new Dictionary<string, string>()
{
    {"ACFT", "AIRCRAFT"},
    {"FT", "FEET"},
};
foreach(string s in replacements.Keys)
{
    inputBox.Text = inputBox.Text.Replace(s, replacements[s]);
}

When I execute the code, if I have ACFT in the textbox, it is replaced with AIRCRAFEET because it sees the FT part in the string. I need to somehow differentiate this and only replace the whole word.

So for example, if I have ACFT in the box, it should replace it with AIRCRAFT. And, if I have FT in the box, replace it with FEET.

So my question is, how can I match whole words only when replacing words?

EDIT: I want to be able to use and replace multiple words.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Nicholas
  • 299
  • 5
  • 12
  • 3
    Try and look at this http://stackoverflow.com/questions/6143642/way-to-have-string-replace-only-hit-whole-words – David Pilkington Oct 30 '14 at 05:46
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Oct 30 '14 at 06:20

5 Answers5

1

use the if condition..

foreach(string s in replacements.Keys) {
    if(inputBox.Text==s){
        inputBox.Text = inputBox.Text.Replace(s, replacements[s]);
    }
}

UPDATE after you modified your question..

 string str = "ACFT FTT";
 Dictionary<string, string> replacements = new Dictionary<string, string>()
 {
     {"ACFT", "AIRCRAFT"},
     {"FT", "FEET"},
 };
 string[] temp = str.Split(' ');
 string newStr = "";
 for (int i = 0; i < temp.Length; i++)
 {

     try
     {
         temp[i] = temp[i].Replace(temp[i], replacements[temp[i]]);
     }
     catch (KeyNotFoundException e)
     {
         // not found..
     }
     newStr+=temp[i]+" ";
 }
 Console.WriteLine(  newStr);
Deepak Sharma
  • 4,124
  • 1
  • 14
  • 31
  • he is talking abt single word till yet.. check what example he gave.. on the basis on that I answered.. if reading answer carefully, must read question carefully before that .. – Deepak Sharma Oct 30 '14 at 05:48
  • Thanks for your suggestion, Deepak. I should have been more clear in my original question; however, your solution does not work if I do have multiple words. – Nicholas Oct 30 '14 at 05:50
1

how can I match whole words only when replacing words?

Use regular expressions (as was suggested by David Pilkington)

Dictionary<string, string> replacements = new Dictionary<string, string>()
{
    {"ACFT", "AIRCRAFT"},
    {"FT", "FEET"},
};

foreach(string s in replacements.Keys)
{
    var pattern = "\b" + s + "\b"; // match on word boundaries
    inputBox.Text = Regex.Replace(inputBox.Text, pattern, replacements[s]);
}

However, if you have control over the design, I would much rather use keys like "{ACFT}","{FT}" (which have explicit boundaries), so you could just use them with String.Replace.

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
0

The problem with this is that you are replacing every instance of the substring in the entire string. If what you want is to replace only whole, space-delimited instances of "ACFT" or "FT", you would want to use String.Split() to create a set of tokens.

For example:

string tempString = textBox1.Text;
StringBuilder finalString = new StringBuilder();
foreach (string word in tempString.Split(new char[] { ' ' })
{
    foreach(string s in replacements.Keys)
    {
        finalString.Append(word.Replace(s, replacements[s]));
    }
}

textBox1.Text = finalString.ToString();

I've used a StringBuilder here because concatenation requires the creation of a new string every single time, and this gets extremely inefficient over long periods. If you expect to have a small number of concatenations to make, you can probably get away with using string.

Note that there's a slight wrinkle in your design - if you have a KeyValuePair with a value that's identical to a key that occurs later in the dictionary iteration, the replacement will be overwritten.

furkle
  • 5,019
  • 1
  • 15
  • 24
0

I think you may want to replace the max length subStr in inputText.

        int maxLength = 0;
        string reStr = "";
        foreach (string s in replacements.Keys)
        {
            if (textBox2.Text.Contains(s))
            {
                if (maxLength < s.Length)
                {
                    maxLength = s.Length;
                    reStr = s;
                }
            }
        }
        if (reStr != "")
            textBox2.Text = textBox2.Text.Replace(reStr, replacements[reStr]);
allen
  • 250
  • 4
  • 13
0

Here's very funky way of doing this.

First up, you need to use regular expressions (Regex) as this has good built-in features for matching word boundaries.

So the key line of code would be to define a Regex instance:

var regex = new Regex(String.Format(@"\b{0}\b", Regex.Escape("ACFT"));

The \b marker looks for word boundaries. The Regex.Escape ensures that if any other your keys have special Regex characters that they are escaped out.

You could then replace the text like this:

var replacedtext = regex.Replace("A FT AFT", "FEET");

You would get replacedtext == "A FEET AFT".

Now, here's the funky part. If you start with your current dictionary then you can define a single function that will do all of the replacements in one go.

Do it this way:

Func<string, string> funcreplaceall =
    replacements
        .ToDictionary(
            kvp => new Regex(String.Format(@"\b{0}\b", Regex.Escape(kvp.Key))),
            kvp => kvp.Value)
        .Select(kvp =>
            (Func<string, string>)(x => kvp.Key.Replace(x, kvp.Value)))
        .Aggregate((f0, f1) => x => f1(f0(x)));

Now you can just call it like so:

inputBox.Text = funcreplaceall(inputBox.Text);

No looping required!

Just as a sanity check I got this:

funcreplaceall("A ACFT FT RACFT B") == "A AIRCRAFT FEET RACFT B"
Enigmativity
  • 113,464
  • 11
  • 89
  • 172