替换字符串中的一个字符,但不能替换两个

问题描述 投票:0回答:7

我想使用 C# 替换字符串中出现的单个字符,而不是两个。

例如,我想用空字符串替换

&
,但当出现的是
&&
时则不行。再比如,替换后
a&b&&c
会变成
ab&&c

如果我使用像

&[^&]
这样的正则表达式,它也会匹配
&
之后的字符,我不想替换它。

我发现的另一个解决方案是迭代字符串字符。

您知道更清洁的解决方案吗?

c# regex
7个回答
7
投票

要仅匹配一个

&
(前后不带
&
),请使用 look-arounds
(?<!&)
(?!&)
:

(?<!&)&(?!&)

参见 正则表达式演示

您尝试使用仍然匹配字符的否定字符类,并且您需要使用前瞻/后视来仅检查某些字符的缺失/存在,而不消耗它。

参见正则表达式.info

如果您想匹配后面没有其他内容的内容,则负向前瞻是必不可少的。在解释 字符类 时,本教程解释了为什么不能使用否定字符类来匹配后面没有

q
u
。负向前瞻提供了解决方案:
q(?!u)

Lookbehind 具有相同的效果,但向后工作。它告诉正则表达式引擎暂时在字符串中后退,以检查向后查找中的文本是否可以在那里匹配。

(?<!a)b
使用负向后查找来匹配前面没有
"b"
"a"
。它与
cab
不匹配,但与床上或债务中的
b
(且仅是
b
)匹配。


6
投票

您可以匹配

&
&&
(或任意数量的重复),并且仅将单个替换为空字符串:

str = Regex.Replace(str, "&+", m => m.Value.Length == 1 ? "" : m.Value);

1
投票

您可以使用此正则表达式:

@"(?<!&)&(?!&)"

var str = Regex.Replace("a&b&&c", @"(?<!&)&(?!&)", "");
Console.WriteLine(str);   // ab&&c

0
投票

你可以这样做:

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

尽可能通用


0
投票

我会使用这样的东西,IMO应该比使用

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

0
投票

我将从评论中为这一声明做出贡献:

在这种情况下,只有奇数个 '&' 的子字符串将被除最后一个 "&" 之外的所有 "&" 替换。 “&&&”将是“&&”,“&&&&”将是“&&&&”

这是一个使用 balancing groups 的非常简洁的解决方案(尽管我不会称它特别干净或易于阅读)。

代码:

string str = "11&222&&333&&&44444&&&&55&&&&&";
str = Regex.Replace(str, "&((?:(?<2>&)(?<-2>&)?)*)", "$1$2");

输出:

11222&&333&&44444&&&&55&&&&

ideone 演示


  1. 它总是匹配第一个
    &
    (未捕获)。
  2. 如果后面跟着偶数个
    &
    ,则将它们匹配并存储在
    $1
    中。第二组被第一组捕获,但随后被第二组减去。
  3. 但是,如果
    &
    的个数为奇数,则可选组
    (?<-2>&)?
    不匹配,并且该组不会被减去。然后,
    $2
    将捕获额外的
    &

例如,匹配主题

"&&&&"
,第一个字符被消耗并且未被捕获(1)。第二个和第三个字符匹配,但
$2
被减去 (2)。对于最后一个字符,捕获
$2
(3)。最后 3 个字符存储在
$1
中,
&
中还有一个额外的
$2

然后,替换
"$1$2" == "&&&&"


0
投票

接受的答案符合要求,但我发现自己在寻找清理字符串中可能包含该字符转义对的字符的单个实例时(例如 CSV 中的双引号

""
或 C# 逐字字符串,或双反斜杠
\\
)。

在这种情况下,环视方法不起作用,因为它不消耗字符,因此仍然单独评估一对中的每个成员。例如,将所有三个

&
保留在
a&&&b
中即可;它不会保留这对并删除多余的单个,使其
a&&b
。为此,您可以匹配
&
,后跟捕获的非
&
,并将整个匹配替换为捕获的值:

&([^&]|$)
替换为
$1

如果您还想同时将双打转义为单打,请更改捕获组以匹配任何字符:

&([^\s\S]|$)
替换为
$1

\s\S
是任何字符,包括换行符。如果
|$
是最后一个字符,则
&
允许删除它。我想这是一个非常微妙的案例 - 我的案例与格式错误的 CSV 文件有关,但希望它能对某人有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.