替换字符串中的一个字符,而不是两个
本文关键字:两个 字符 字符串 替换 一个 | 更新日期: 2023-09-27 18:16:39
我想用c#替换字符串中出现的单个字符,而不是两个字符。
例如,我想用空字符串替换&
,但当出现&&
时不替换。又如,a&b&&c
替换后会变成ab&&c
。
如果我使用像&[^&]
这样的正则表达式,它也将匹配&
之后的字符,我不想替换它。
你知道一个更干净的解决方案吗?
如果只匹配一个&
(前面或后面没有&
),请使用查找 (?<!&)
和(?!&)
:
(?<!&)&(?!&)
参见regex demo
您尝试使用一个仍然匹配字符的否定字符类,并且您需要使用向前看/向后看来检查一些字符的缺失/存在,而不消耗它。
看到regular-expressions.info:
如果你想匹配某个内容而不是后面跟着其他内容,那么负向前看是必不可少的。在解释字符类时,本教程解释了为什么不能使用否定的字符类来匹配不后跟
u
的q
。负向前看提供了解决方案:q(?!u)
.Lookbehind具有相同的效果,但向后工作。它告诉regex引擎在字符串中暂时向后步进,检查后面的文本是否可以在那里匹配。
(?<!a)b
匹配前面没有"a"
的"b"
,使用负向后看。它与cab
不匹配,但与b
(仅与b
)在床上或债务中匹配。
您可以匹配&
和&&
(或任何数量的重复),并且仅将单个替换为空字符串:
str = Regex.Replace(str, "&+", m => m.Value.Length == 1 ? "" : m.Value);
你可以使用这个正则表达式:@"(?<!&)&(?!&)"
var str = Regex.Replace("a&b&&c", @"(?<!&)&(?!&)", "");
Console.WriteLine(str); // ab&&c
你可以这样做:
public static string replacement(string oldString, char charToRemove)
{
string newString = "";
bool found = false;
foreach (char c in oldString)
{
if (c == charToRemove && !found)
{
found = true;
continue;
}
newString += c;
}
return newString;
}
这是尽可能通用的
我会使用这样的东西,这在我看来应该比使用Regex
:
public static class StringExtensions
{
public static string ReplaceFirst(this string source, char oldChar, char newChar)
{
if (string.IsNullOrEmpty(source)) return source;
int index = source.IndexOf(oldChar);
if (index < 0) return source;
var chars = source.ToCharArray();
chars[index] = newChar;
return new string(chars);
}
}
我将从注释中贡献这句话:
在这种情况下,只有含有奇数个'&'的子字符串将被除最后一个'&'之外的所有'&'替换。. ",,,"是",和"answers",,,,"将",,,,"
这是一个使用平衡组的非常简洁的解决方案(尽管我不认为它特别干净,也不容易阅读)。
代码:
string str = "11&222&&333&&&44444&&&&55&&&&&";
str = Regex.Replace(str, "&((?:(?<2>&)(?<-2>&)?)*)", "$1$2");
输出:11222&&333&&44444&&&&55&&&&
<<p> ideone演示/kbd> - 它总是匹配第一个
&
(未捕获)。 - 如果后面跟着偶数
&
,它们匹配并存储在$1
中。第二组被第一组捕获,但随后被第二组减去。 - 但是,如果
&
有奇数,则可选组(?<-2>&)?
不匹配,不减法。然后,$2
将捕获一个额外的&
例如,匹配主题"&&&&"
,第一个字符被消耗,它不被捕获(1)。第二个和第三个字符被匹配,但是$2
被减去(2)。对于最后一个字符,捕获$2
(3)。最后3个字符存储在$1
中,$2
中还有一个额外的&
。
然后,替换"$1$2" == "&&&&"
.