简体   繁体   English

字符串替换为字典值

[英]String Replace with Dictionary Values

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. 执行代码时,如果文本框中有ACFT ,则将它替换为AIRCRAFEET因为它在字符串中看到FT部分。 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 . 因此,例如,如果我的包装盒中有ACFT ,则应将其替换为AIRCRAFT And, if I have FT in the box, replace it with FEET . 而且,如果我的包装盒中有FT ,请用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. 编辑:我希望能够使用和替换多个单词。

how can I match whole words only when replacing words? 在替换单词时,我怎么才能匹配整个单词?

Use regular expressions (as was suggested by David Pilkington) 使用正则表达式(如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 . 但是,如果您可以控制设计,那么我宁愿使用诸如"{ACFT}""{FT}" (它们具有明确的边界),因此您可以将它们与String.Replace一起使用。

use the if condition.. 使用if条件。

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);

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. 如果要替换的是仅完整的,用空格分隔的“ ACFT”或“ FT”实例,则需要使用String.Split()创建一组令牌。

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. 我在这里使用StringBuilder是因为串联需要每次都创建一个新字符串,而且长期来看效率极低。 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. 请注意,您的设计中存在一些细微的变化-如果您的KeyValuePair的值与随后在字典迭代中出现的键相同,则替换将被覆盖。

I think you may want to replace the max length subStr in inputText. 我认为您可能要替换inputText中的最大长度subStr。

        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]);

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. 首先,您需要使用正则表达式( Regex ),因为它具有良好的内置功能以匹配单词边界。

So the key line of code would be to define a Regex instance: 因此,代码的关键行是定义Regex实例:

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

The \\b marker looks for word boundaries. \\b标记查找单词边界。 The Regex.Escape ensures that if any other your keys have special Regex characters that they are escaped out. Regex.Escape确保如果您的其他任何键都有特殊的Regex字符,则可以将它们转义出去。

You could then replace the text like this: 然后,您可以像这样替换文本:

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

You would get replacedtext == "A FEET AFT" . 您将获得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"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM