替换字符串中的许多可变长度占位符
Replace many variable-length placeholders in string
晚上好,
我正在尝试查找所有出现的以“{”开头并以“}”结尾的字符串,然后将它们替换为不同的字符串。为了帮助说明,下面是一个简短的例子。
string exampleString = "My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}.";
在上面的字符串中,我想删除 {Name}、{Race}、{Height} 和 {HairLength},并用其他内容替换它们。我现在在使用子字符串时遇到了问题,我想,因为我似乎无法在正确的位置拆分字符串,只能删除括号中的单词。
我想我已经为此精疲力尽,并且犯了一些愚蠢的错误,但我现在看不到它们。下面是我用来拆分字符串的(混乱的)代码。
public static string ForPlayer ( string originalString )
{
string richText = originalString;
PropertyInfo propertyInfo;
int openingInstance = 0;
int closingInstance = 0;
int length = 0;
foreach ( char c in originalString.ToCharArray ())
{
if ( c == '{' )
{
openingInstance = length;
}
if ( c == '}' && openingInstance > closingInstance )
{
int lastBrace = closingInstance;
closingInstance = length;
int lengthToNextBrace = originalString.IndexOf ( "{", closingInstance ) - closingInstance - 1;
string richInstance = originalString.Substring ( openingInstance + 1, closingInstance - openingInstance - 1 );
propertyInfo = Player.player.GetType ().GetProperty ( richInstance );
if ( propertyInfo != null )
{
string beginning;
string end;
if ( lastBrace == 0 )
{
beginning = originalString.Substring ( 0, openingInstance );
} else
{
beginning = originalString.Substring ( closingInstance + 1, openingInstance - lastBrace );
}
if ( lengthToNextBrace > -1 )
{
end = originalString.Substring ( closingInstance + 1, lengthToNextBrace );
} else
{
end = originalString.Substring ( closingInstance + 1, originalString.Length - closingInstance - 1 );
}
richText = beginning + propertyInfo.GetValue ( Player.player, null ) + end;
UnityEngine.Debug.Log ( beginning + propertyInfo.GetValue ( Player.player, null ) + end );
}
}
length += 1;
}
return richText;
}
我得到:
DEBUG: "My name is default. I was born as "
DEBUG: ". I am {Height} tdefault. I am "
DEBUG: " tall. Mdefault tall. My hair is "
ERROR: "ArgumentOutOfRangeException: startIndex + length > this.length"
我愿意:
My name is defaultName. I was born as
defaultRace. I am
defaultHeight tall. My hair is
defaultHairLength.
===编辑===
谢谢大家的解答!不幸的是,我不知道我想要替换的字符串是什么,而且有很多可能性,如果可能的话,我宁愿使用我目前通过反射找到它的方法。
var replacement=new Dictionary<string,string>{
{"Name","defaultName"},
{"Race","defaultRace"},
{"Height","defaultHeight"},
{"HairLength","defaultHairLength"}
};
string exampleString="My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}.";
foreach(var kv in replacement)
{
exampleString = exampleString.Replace("{" + kv.Key + "}", kv.Value);
}
从 PetSerAl 窃取第一部分
这是我使用正则表达式的方法。
using System.Text.RegularExpressions;
...
class Program
{
static int occurence = 0;
static string[] defValues = new string[] { "DefName", "DefRace", "DefHeight", "DefHair" };
static string ReplaceWithDefault(Match m)
{
if (occurence < defValues.Length)
return defValues[occurence++];
else
return "NO_DEFAULT_VALUE_FOUND";
}
static void Main(string[] args)
{
string exampleString = "My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}.";
string replaced = Regex.Replace(exampleString, "\{[^\}]+\}", new MatchEvaluator(ReplaceWithDefault));
occurence = 0;
Console.WriteLine(exampleString);
Console.WriteLine(replaced);
}
}
试试这个:
public static string ForPlayer(string originalString)
{
return
Regex
.Matches(originalString, "{(.*?)}")
.Cast<Match>()
.Select(x => x.Groups[1].Value)
.Select(x => new
{
From = x,
To = Player.player
.GetType()
.GetProperty(x)
.GetValue(Player.player)
.ToString()
})
.Aggregate(originalString, (a, x) => a.Replace("{" + x.From + "}", x.To));
}
我使用以下测试 class:
在您的样本输入 "My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}."
上测试了这个
public class Player
{
public string Name {get; set; }
public string Race {get; set; }
public string Height {get; set; }
public int HairLength {get; set; }
}
var player = new Player()
{
Name = "Fred", Race = "English", Height = "Tall", HairLength = 33
};
得到这个结果:
"My name is Fred. I was born as English. I am Tall tall. My hair is 33."
这个更好:
public static string ForPlayer(string originalString)
{
return
Regex
.Replace(originalString, "{(.*?)}", m =>
Player.player
.GetType()
.GetProperty(m.Groups[1].Value)
.GetValue(Player.player)
.ToString());
}
如果占位符实际上是 属性 对象的名称,那么您可以利用 FormatWith
来完成这项工作。
string exampleString = "My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}.";
string replacedString = exampleString.FormatWith(Player.player);
这是一个干净、简单的版本。它使用 IndexOf
方法查找大括号而不是遍历字符。它还使用 StringBuilder
来尽可能避免复制字符串。
public static string ForPlayer(string originalString, object player)
{
var type = player.GetType();
var sb = new StringBuilder(originalString.Length);
var lastEnd = 0; // after the last close brace
var start = originalString.IndexOf('{'); // start brace
while (start != -1) // go until we run out of open braces
{
var end = originalString.IndexOf('}', start + 1); // end brace
if (end == -1) // if there's a start brace but no end, just quit
break;
// copy from the end of the last string to the start of the new one
sb.Append(originalString, lastEnd, start - lastEnd);
// get the name of the property to look up
var propName = originalString.Substring(start + 1, end - start - 1);
// add in the property value
sb.Append(type.GetProperty(propName).GetValue(player, null));
lastEnd = end + 1; // move the pointer to the end of the last string
start = originalString.IndexOf('{', lastEnd); // find the next start
}
// copy the end of the string
sb.Append(originalString, lastEnd, originalString.Length - lastEnd);
return sb.ToString();
}
晚上好,
我正在尝试查找所有出现的以“{”开头并以“}”结尾的字符串,然后将它们替换为不同的字符串。为了帮助说明,下面是一个简短的例子。
string exampleString = "My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}.";
在上面的字符串中,我想删除 {Name}、{Race}、{Height} 和 {HairLength},并用其他内容替换它们。我现在在使用子字符串时遇到了问题,我想,因为我似乎无法在正确的位置拆分字符串,只能删除括号中的单词。
我想我已经为此精疲力尽,并且犯了一些愚蠢的错误,但我现在看不到它们。下面是我用来拆分字符串的(混乱的)代码。
public static string ForPlayer ( string originalString )
{
string richText = originalString;
PropertyInfo propertyInfo;
int openingInstance = 0;
int closingInstance = 0;
int length = 0;
foreach ( char c in originalString.ToCharArray ())
{
if ( c == '{' )
{
openingInstance = length;
}
if ( c == '}' && openingInstance > closingInstance )
{
int lastBrace = closingInstance;
closingInstance = length;
int lengthToNextBrace = originalString.IndexOf ( "{", closingInstance ) - closingInstance - 1;
string richInstance = originalString.Substring ( openingInstance + 1, closingInstance - openingInstance - 1 );
propertyInfo = Player.player.GetType ().GetProperty ( richInstance );
if ( propertyInfo != null )
{
string beginning;
string end;
if ( lastBrace == 0 )
{
beginning = originalString.Substring ( 0, openingInstance );
} else
{
beginning = originalString.Substring ( closingInstance + 1, openingInstance - lastBrace );
}
if ( lengthToNextBrace > -1 )
{
end = originalString.Substring ( closingInstance + 1, lengthToNextBrace );
} else
{
end = originalString.Substring ( closingInstance + 1, originalString.Length - closingInstance - 1 );
}
richText = beginning + propertyInfo.GetValue ( Player.player, null ) + end;
UnityEngine.Debug.Log ( beginning + propertyInfo.GetValue ( Player.player, null ) + end );
}
}
length += 1;
}
return richText;
}
我得到:
DEBUG: "My name is default. I was born as "
DEBUG: ". I am {Height} tdefault. I am "
DEBUG: " tall. Mdefault tall. My hair is "
ERROR: "ArgumentOutOfRangeException: startIndex + length > this.length"
我愿意:
My name is defaultName. I was born as
defaultRace. I am
defaultHeight tall. My hair is
defaultHairLength.
===编辑===
谢谢大家的解答!不幸的是,我不知道我想要替换的字符串是什么,而且有很多可能性,如果可能的话,我宁愿使用我目前通过反射找到它的方法。
var replacement=new Dictionary<string,string>{
{"Name","defaultName"},
{"Race","defaultRace"},
{"Height","defaultHeight"},
{"HairLength","defaultHairLength"}
};
string exampleString="My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}.";
foreach(var kv in replacement)
{
exampleString = exampleString.Replace("{" + kv.Key + "}", kv.Value);
}
从 PetSerAl 窃取第一部分
这是我使用正则表达式的方法。
using System.Text.RegularExpressions;
...
class Program
{
static int occurence = 0;
static string[] defValues = new string[] { "DefName", "DefRace", "DefHeight", "DefHair" };
static string ReplaceWithDefault(Match m)
{
if (occurence < defValues.Length)
return defValues[occurence++];
else
return "NO_DEFAULT_VALUE_FOUND";
}
static void Main(string[] args)
{
string exampleString = "My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}.";
string replaced = Regex.Replace(exampleString, "\{[^\}]+\}", new MatchEvaluator(ReplaceWithDefault));
occurence = 0;
Console.WriteLine(exampleString);
Console.WriteLine(replaced);
}
}
试试这个:
public static string ForPlayer(string originalString)
{
return
Regex
.Matches(originalString, "{(.*?)}")
.Cast<Match>()
.Select(x => x.Groups[1].Value)
.Select(x => new
{
From = x,
To = Player.player
.GetType()
.GetProperty(x)
.GetValue(Player.player)
.ToString()
})
.Aggregate(originalString, (a, x) => a.Replace("{" + x.From + "}", x.To));
}
我使用以下测试 class:
在您的样本输入"My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}."
上测试了这个
public class Player
{
public string Name {get; set; }
public string Race {get; set; }
public string Height {get; set; }
public int HairLength {get; set; }
}
var player = new Player()
{
Name = "Fred", Race = "English", Height = "Tall", HairLength = 33
};
得到这个结果:
"My name is Fred. I was born as English. I am Tall tall. My hair is 33."
这个更好:
public static string ForPlayer(string originalString)
{
return
Regex
.Replace(originalString, "{(.*?)}", m =>
Player.player
.GetType()
.GetProperty(m.Groups[1].Value)
.GetValue(Player.player)
.ToString());
}
如果占位符实际上是 属性 对象的名称,那么您可以利用 FormatWith
来完成这项工作。
string exampleString = "My name is {Name}. I was born as {Race}. I am {Height} tall. My hair is {HairLength}.";
string replacedString = exampleString.FormatWith(Player.player);
这是一个干净、简单的版本。它使用 IndexOf
方法查找大括号而不是遍历字符。它还使用 StringBuilder
来尽可能避免复制字符串。
public static string ForPlayer(string originalString, object player)
{
var type = player.GetType();
var sb = new StringBuilder(originalString.Length);
var lastEnd = 0; // after the last close brace
var start = originalString.IndexOf('{'); // start brace
while (start != -1) // go until we run out of open braces
{
var end = originalString.IndexOf('}', start + 1); // end brace
if (end == -1) // if there's a start brace but no end, just quit
break;
// copy from the end of the last string to the start of the new one
sb.Append(originalString, lastEnd, start - lastEnd);
// get the name of the property to look up
var propName = originalString.Substring(start + 1, end - start - 1);
// add in the property value
sb.Append(type.GetProperty(propName).GetValue(player, null));
lastEnd = end + 1; // move the pointer to the end of the last string
start = originalString.IndexOf('{', lastEnd); // find the next start
}
// copy the end of the string
sb.Append(originalString, lastEnd, originalString.Length - lastEnd);
return sb.ToString();
}