C#/.NET中的可变字符串编辑
我想在.NET应用程序中就地获取和编辑字符串。我知道,C#/.NET中的可变字符串编辑,c#,.net,C#,.net,我想在.NET应用程序中就地获取和编辑字符串。我知道,StringBuilder允许我进行就地追加、插入和替换,但它不允许以一种简单的方式进行以下操作: while (script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCase) != -1) { int Location = script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCas
StringBuilder
允许我进行就地追加、插入和替换,但它不允许以一种简单的方式进行以下操作:
while (script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCase) != -1)
{
int Location = script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCase);
script = script.Remove(Location, 7);
script = script.Insert(Location, Guid.NewGuid().ToString());
}
因为StringBuilder
中没有IndexOf
。是否有人有一种有效的方法来对文本信息进行就地编辑
编辑#1:
更改了示例,使每个“替换”都需要不同的结果更加明显。StringBuilder的制作使您可以轻松添加到其中,但折衷是很难在其中搜索,尤其是索引它更困难(即速度较慢)。 如果需要“就地”修改某些字符,最好在生成的字符串上进行修改
但是很难从你的问题中知道什么是适合你的正确答案,我的感觉是你不需要在StringBuilder中进行就地更换,问题出在其他地方/你做错了什么。如果你的代码真的这么简单,那么为什么不使用一个内置的
Replace
方法
编辑以下评论…
您可以使用以下参数将每个引用替换为单独的值:
string foo = "blah blah @Unique blah @Unique blah blah @Unique blah";
// replace each occurrence of "@Unique" with a separate guid
string bar = Regex.Replace(foo, "@Unique",
new MatchEvaluator(m => Guid.NewGuid().ToString()),
RegexOptions.IgnoreCase));
如何使用StringBuilder方法:
你要更换多少人 如果不是四位数,那么只接受新的字符串实例,您可能过早地优化了
另一个解决方案。。。在“@uniqueID”上拆分,然后重新加入StringBuilder,为每次迭代添加分隔符。您能使用字符串拆分有效地完成此操作吗 比如:
var sections = "a-@Unique-b-@Unique-c".Split(new string[] { "@Unique" }, StringSplitOptions.None);
int i;
StringBuilder builder = new StringBuilder();
for(i = 0; i < sections.Length - 1; i++)
{
builder.Append(sections[i]);
builder.Append(Guid.NewGuid().ToString());
}
builder.Append(sections[i]);
Console.WriteLine(builder.ToString());
Console.ReadKey(true);
var sections=“a-@Unique-b-@Unique-c”.Split(新字符串[]{“@Unique”},StringSplitOptions.None);
int i;
StringBuilder=新的StringBuilder();
对于(i=0;i
您需要使用非托管代码块
简单到声明一个指向字符串的指针并在内存中操作它
范例
unsafe
{
char* ip;
ip = &to_your_string;
}
用户Dennis提供了一个。有了它,您应该能够以这种方式使用StringBuilder。很复杂,但应该是一个性能良好的解决方案
public StringBuilder Replace(this StringBuilder sb, string toReplace, Func<string> getReplacement)
{
for (int i = 0; i < sb.Length; i++)
{
bool replacementFound = true;
for (int toReplaceIndex = 0; toReplaceIndex < toReplace.Length; toReplaceIndex++)
{
int sbIndex = toReplaceIndex + i;
if (sbIndex < sb.Length)
{
return sb;
}
if (sb[sbIndex] != toReplace[toReplaceIndex])
{
replacementFound = false;
break;
}
}
if (replacementFound)
{
string replacement = getReplacement();
// reuse the space of the toReplace string
for (int replacementIndex = 0; replacementIndex < toReplace.Length && replacementIndex < replacement.Length; replacementIndex++)
{
int sbIndex = replacementIndex + i;
sb[sbIndex] = replacement[i];
}
// remove toReplace string remainders
if (replacement.Length < toReplace.Length)
{
sb.Remove(i + replacement.Length, replacement.Length - toReplace.Length)
}
// insert chars not yet inserted
if (replacement.Length > toReplace.Length)
{
sb.Insert(i + toReplace.Length, replacement.ToCharArray(toReplace.Length, toReplace.Length - replacement.Length));
}
}
}
return sb;
}
我的问题是,在上面的示例中,@Unique的每个实例都需要不同的值,因此我无法在字符串中进行全局查找和替换。@JasonRShaver:这可以使用
Regex.replace
完成。看看我的编辑。@Luke:这个解决方案看起来不错,但它是否支持StringBuilder,就像在需求中一样。我猜“JasonRShaver”可以用问题中的字符串完成。这是一个非常有趣的解决方案。我很好奇regex处理器在内存方面的表现如何。MatchEvaluator对我来说也是新的,我很高兴现在就“知道”了。稍后我将对此方法制作一个测试应用程序,看看它是否完全解决了问题。@JasonRShaver这些方法在内部使用StringBuilder
(并执行一些子串接),因此应该相当有效。我刚刚意识到,necro comment:-DIf字符串有两个@Unique,那么两个替换将具有相同的值,而不是唯一的值。这就是为什么他不想使用IndexOf,所以每次替换都会生成一个新的唯一值。我认为StringBuilder不能在这种情况下使用。您只需将其作为字符串进行处理,可能您可以在将其添加到StringBuilder之前对其进行处理。系统将在我们预期的峰值处理大约300000项。@Jason-在峰值负载下,此方法的性能规格是什么?执行一个实现并在加载时对其进行基准测试。如果符合规格,请发货。如果没有,请分析它+1.看起来不安全不允许您声明指向字符串的指针。对不起的:(1)这是几个月以来我见过的最可怕的C代码,我甚至不会考虑做这样的事情。我很高兴.NET设计者保证它不会起作用。@ TruteWr:不幸的是,很容易对现有字符串进行突变。<代码>字符串类有私有<代码> AppDeNePix< /Calp>,<代码>可以使用反射来调用这些方法。但是我同意你的观点,甚至在任何真实世界代码中考虑使用这些方法都是疯狂的。对不起,TrueWill我并不是想让你哭……但是不安全是.NETFramework的一部分,而.NET设计者是设计它的。这是一个不同的故事。
public StringBuilder Replace(this StringBuilder sb, string toReplace, Func<string> getReplacement)
{
for (int i = 0; i < sb.Length; i++)
{
bool replacementFound = true;
for (int toReplaceIndex = 0; toReplaceIndex < toReplace.Length; toReplaceIndex++)
{
int sbIndex = toReplaceIndex + i;
if (sbIndex < sb.Length)
{
return sb;
}
if (sb[sbIndex] != toReplace[toReplaceIndex])
{
replacementFound = false;
break;
}
}
if (replacementFound)
{
string replacement = getReplacement();
// reuse the space of the toReplace string
for (int replacementIndex = 0; replacementIndex < toReplace.Length && replacementIndex < replacement.Length; replacementIndex++)
{
int sbIndex = replacementIndex + i;
sb[sbIndex] = replacement[i];
}
// remove toReplace string remainders
if (replacement.Length < toReplace.Length)
{
sb.Remove(i + replacement.Length, replacement.Length - toReplace.Length)
}
// insert chars not yet inserted
if (replacement.Length > toReplace.Length)
{
sb.Insert(i + toReplace.Length, replacement.ToCharArray(toReplace.Length, toReplace.Length - replacement.Length));
}
}
}
return sb;
}
var sb = new StringBuilder(script);
script = sb.Replace("@Unique", () => Guid.NewGuid().ToString()).ToString();