简体   繁体   中英

Replacing dynamic variable in string UNITY

I am making a simple dialogue system, and would like to "dynamise" some of the sentences. For exemple, I have a Sentence

Hey Adventurer {{PlayerName}} ! Welcome in the world !

Now In code I am trying to replace that by the real value of the string in my game. I am doing something like this. But it doesn't work. I do have a string PlayerName in my component where the function is situated

Regex regex = new Regex("(?<={{)(.*?)(?=}})");
MatchCollection matches = regex.Matches(sentence);

for(int i = 0; i < matches.Count; i++)
{
    Debug.Log(matches[i]);
    sentence.Replace("{{"+matches[i]+"}}", this.GetType().GetField(matches[i].ToString()).GetValue(this) as string);
}
return sentence;

But this return me an error, even tho the match is correct.

Any idea of a way to do fix, or do it better?

Here's how I would solve this.

Create a dictionary with keys as the values you wish to replace and values as what you will be replacing them to.

Dictionary<string, string> valuesToReplace;
valuesToReplace = new Dictionary<string, string>();
    valuesToReplace.Add("[playerName]", "Max");
    valuesToReplace.Add("[day]", "Thursday");

Then check the text for the values in your dictionary. If you make sure all of your keys start with "[" and end with "]" this will be quick and easy.

List<string> replacements = new List<string>(); 
    //We will save all of the replacements we are about to perform here.
    //This is done so we won't be modifying the original string while working on it, which will create problems.
    //We will save them in the following format:  originalText}newText

    for(int i = 0; i < text.Length; i++) //Let's loop through the entire text
    {
        int startOfVar = 9999;
        if(text[i] == '[') //We have found the beginning of a variable
        {
            startOfVar = i;
        }
        if(text[i] == ']') //We have found the ending of a variable
        {
            string replacement = text.Substring(startOfVar, i - startOfVar); //We have found the section we wish to replace
            if (valuesToReplace.ContainsKey(replacement))
                replacements.Add(replacement + "}" + valuesToReplace[replacement]); //Add the replacement we are about to perform to our dictionary
        }
    }
    //Now let's perform the replacements:

    foreach(string replacement in replacements)
    {
        text = text.Replace(replacement.Split('}')[0], replacement.Split('}')[1]); //We split our line. Remember the old value was on the left of the } and the new value was on the right
    }

This will also work much faster, since it allows you to add as many variables as you wish without making the code slower.

Using Regex.Replace method, and a MatchEvaluator delegate (untested):

    Dictionary<string, string> Replacements = new Dictionary<string, string>();
    Regex DialogVariableRegex = new Regex("(?<={{)(.*?)(?=}})");

    string Replace(string sentence) {

        DialogVariableRegex.Replace(sentence, EvaluateMatch);

        return sentence;
    }

    string EvaluateMatch(Match match) {

        var matchedKey = match.Value;

        if (Replacements.ContainsKey(matchedKey))
            return Replacements[matchedKey];
        else
            return ">>MISSING KEY<<";
    }

This is kind of old now, but I figured I'd update the accepted code above. It won't work since the start index is reset every time the loop iterates, so setting startOfVar = i gets completely reset by the time it hits the closing character. Plus there are problems if there's an open bracket '[' and no closing one. You can also no longer use those brackets in your text.

There's also setting the splitter to a single character. It tests fine, but if I set my player name to "Rob}ert", that will cause problems when it performs the replacements.

Here is my updated take on the code which I've tested works in Unity:

    public string EvaluateVariables(string str)
    {
        Dictionary<string, string> varDict = GetVariableDictionary();
        List<string> varReplacements = new List<string>();
        string matchGuid = Guid.NewGuid().ToString();
        bool matched = false;

        int start = int.MaxValue;
        for (int i = 0; i < str.Length; i++)
        {
            if (str[i] == '{')
            {
                if (str[i + 1] == '$')
                {
                    start = i;
                    matched = true;
                }
            }
            else if (str[i] == '}' && matched)
            {
                string replacement = str.Substring(start, (i - start) + 1);
                if (varDict.ContainsKey(replacement))
                {
                    varReplacements.Add(replacement + matchGuid + varDict[replacement]);
                }
                start = int.MaxValue;
                matched = false;
            }
        }

        foreach (string replacement in varReplacements)
        {
            str = str.Replace(replacement.Split(new string[] { matchGuid }, StringSplitOptions.None)[0], replacement.Split(new string[] { matchGuid }, StringSplitOptions.None)[1]);
        }

        return str;
    }

    private Dictionary<string, string> GetVariableDictionary()
    {
        Dictionary<string, string> varDict = new Dictionary<string, string>();
        varDict.Add("{$playerName}", playerName);
        varDict.Add("{$npcName}", npcName);
        return varDict;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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