如何从字符串中仅删除特定的子字符串?

21

使用C#,我有一个包含多个查询的SQL脚本字符串。我想删除字符串中用单引号括起来的部分。我可以通过以下方式使用Regex.Replace来实现:

string test = "Only 'together' can we turn him to the 'dark side' of the Force";
test = Regex.Replace(test, "'[^']*'", string.Empty);

结果为: "只有我们才能将他引向原力之 '黑暗面' "

我想要做的是删除引号中的子字符串,除了包含特定子字符串的子字符串。例如,使用上面的字符串,我想要删除带引号的子字符串,除了那些包含"dark"的子字符串,得到的结果字符串应该是:

结果为: "只有我们才能将他引向原力之 '黑暗面' "

如何使用Regex.Replace或其他技术实现呢?我目前正在尝试一种解决方案,它涉及到使用Substring()IndexOf()Contains()

注意:我不在乎围绕“dark side”的单引号是否被删除,因此结果也可以是:“只有我们才能将他引向原力之黑暗面。”我这么说是因为使用Split()的解决方案会删除所有单引号。

编辑: 我还没有使用Substring()IndexOf()等找到解决方案。通过“工作”,我指的是正在脑海中考虑如何完成。我没有任何代码,这就是为什么我还没有发布任何代码。谢谢。

编辑: VKS的解决方案有效。第一次尝试时我没有转义\b,所以它失败了。此外,除非也包括整个字符串周围的单引号,否则它不起作用。

test = Regex.Replace(test, "'(?![^']*\\bdark\\b)[^']*'", string.Empty);

13
您认为这不是在这里提问的好方式,是什么让您这样想的?这是我最近看到的较为完整的首帖之一。使用了正则表达式做了很好的尝试,问题也很明确,还有一些想法。我真的看不出如何能够更好,除非是包含具体答案以外。 - Matthew Haugen
7
@AndyKorneyev的代码中的两行展示了他的努力,是吗?此外,问题写得很好,显示出非常好的研究努力。 - Sriram Sakthivel
4
如果提问者知道自己想要什么,他为什么要首先来到这里呢?好的。那段代码没有展示在这里,我同意,提问者应该将它发布出来。但你说的“这不是在这里询问问题的好方法。你已经尝试过解决问题了吗?”是什么意思?嗯?它似乎是你复制粘贴的通用模板,根本不适用于这个问题。 - Sriram Sakthivel
6
@AndyKorneyev 我不明白为什么我的帖子不是在这里提问的好方法,你能详细说明一下吗?我尝试使用Regex.Replace进行了许多尝试,但我要么删除了所有分隔的子字符串,要么删除了第一个分隔符之后的剩余字符串,要么根本没有变化。我包含了让我最接近想要的结果的代码,也就是我在解决这个问题时做出的努力。我不知道如何解决这个问题,这就是为什么我在这个网站上寻求建议的原因。谢谢你的帮助。 - armus47
7
在SQL中查找单引号通常意味着你的做法是错误的:使用参数化来解决这个问题是更好的方法。 - Marc Gravell
显示剩余10条评论
5个回答

23
'(?![^']*\bdark\b)[^']*'

试试这个。看演示。通过用空字符串替换。你可以在这里使用预查来检查''是否包含单词dark

https://www.regex101.com/r/rG7gX4/12


这是一个很棒的网站,但我无法在我的C#应用程序中让它工作。我使用了“代码生成器”功能并复制了它,但它对字符串没有任何影响。我需要更多地了解正则表达式的语法,以便能够熟练地进行翻译。谢谢! - armus47
可以了!有点小问题,你在评论中漏掉了将整个正则表达式字符串用单引号括起来的部分,我会在我的帖子中加上它。谢谢! - armus47
6
在这种情况下最好使用一个保持原样的字符串,这样你就不需要转义反斜杠:Regex.Replace(test, @"'(?![^']*\bdark\b)[^']*'", string.Empty) - Lucas Trzesniewski

16

虽然vks的解决方案可行,但我想展示一种不同的方法:

string test = "Only 'together' can we turn him to the 'dark side' of the Force";
test = Regex.Replace(test, @"'[^']*'", match => {
    if (match.Value.Contains("dark"))
        return match.Value;

    // You can add more cases here

    return string.Empty;
});

或者,如果您的情况足够简单:

test = Regex.Replace(test, @"'[^']*'", match => match.Value.Contains("dark")
    ? match.Value
    : string.Empty
);

也就是说,使用lambda函数来提供替换的回调函数。这样,您可以运行任意逻辑来替换字符串。


1
这个完美地运作了,而且正是我在寻找的答案。我无法让vks的解决方案起作用,但那是一个相当聪明的网站。Vignesh的解决方案是我试图解决不使用Regex的方法。但我喜欢这个解决方案,因为它使用了Regex和额外的逻辑来实现易于理解的方法。谢谢! - armus47

4

这样的内容可以奏效。
您可以将想要保留的所有字符串添加到excludedStrings数组中。

        string test = "Only 'together' can we turn him to the 'dark side' of the Force";

        var excludedString = new string[] { "dark side" };

        int startIndex = 0;

        while ((startIndex = test.IndexOf('\'', startIndex)) >= 0)
        {
            var endIndex = test.IndexOf('\'', startIndex + 1);
            var subString = test.Substring(startIndex, (endIndex - startIndex) + 1);
            if (!excludedString.Contains(subString.Replace("'", "")))
            {
                test = test.Remove(startIndex, (endIndex - startIndex) + 1);
            }
            else
            {
                startIndex = endIndex + 1;
            }
        }

2
这正是我在无法使用正则表达式时所考虑的方法。你能够如此迅速地完成它,让我印象深刻。谢谢! - armus47

2

另一种方法是使用正则表达式的交替运算符|

@"('[^']*\bdark\b[^']*')|'[^']*'"

然后用$1替换匹配到的字符。

示例

string str = "Only 'together' can we turn him to the 'dark side' of the Force";
string result = Regex.Replace(str, @"('[^']*\bdark\b[^']*')|'[^']*'", "$1");
Console.WriteLine(result);

IDEONE

解释:

  • (...) 是所谓的捕获组

  • '[^']*\bdark\b[^']*' 匹配所有包含子串 dark 的单引号字符串。其中 [^']* 匹配除了 ' 之外的任意字符,零次或多次。

  • ('[^']*\bdark\b[^']*'),因为正则表达式在一个捕获组中,所有匹配的字符都存储在组索引1中。

  • | 接下来是替换运算符

  • '[^']*' 现在匹配所有剩余的(不包括包含 dark 子串的)单引号字符串。请注意,这不会匹配包含子串 dark 的单引号字符串,因为我们已经使用位于 | 替换运算符之前的模式匹配了这些字符串。

  • 最后,用组索引1中的字符替换所有匹配的字符即可得到所需的输出。


1

我尝试了一种你可能在考虑的方法(使用splitContain等解决方案,而不使用regex

string test = "Only 'together' can we turn him to the 'dark side' of the Force";
string[] separated = test.Split('\'');

string result = "";

for (int i = 0; i < separated.Length; i++)
{
    string str = separated[i];
    str = str.Trim();   //trim the tailing spaces

    if (i % 2 == 0 || str.Contains("dark")) // you can expand your condition
    {
       result += str+" ";  // add space after each added string
    }
}
result = result.Trim(); //trim the tailing space again

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接