C# - 从另一个字符串中删除第一次出现的子字符串的最简单方法

Vac*_*ano 72 c# string

我需要从另一个字符串中删除第一个(并且只是第一个)字符串.

这是替换字符串的示例"\\Iteration".这个:

ProjectName\\Iteration\\Release1\\Iteration1

会成为这样的:

ProjectName\\Release1\\Iteration1

这里有一些代码执行此操作:

const string removeString = "\\Iteration";
int index = sourceString.IndexOf(removeString);
int length = removeString.Length;
String startOfString = sourceString.Substring(0, index);
String endOfString = sourceString.Substring(index + length);
String cleanPath = startOfString + endOfString;
Run Code Online (Sandbox Code Playgroud)

这似乎是很多代码.

所以我的问题是:是否有更清晰/更可读/更简洁的方法来做到这一点?

Luk*_*keH 131

int index = sourceString.IndexOf(removeString);
string cleanPath = (index < 0)
    ? sourceString
    : sourceString.Remove(index, removeString.Length);
Run Code Online (Sandbox Code Playgroud)

  • 对于涉及非ASCII字符的字符串,此答案可能会中断.例如,在en-US文化下,`æ`和`ae`被认为是平等的.试图从'Encyclopædia`中删除'paedia`将抛出一个'ArgumentOutOfRangeException`,因为当匹配的子字符串只包含5时,你试图删除6个字符. (10认同)
  • 我们可以像这样修改它:`sourceString.IndexOf(removeString,StringComparison.Ordinal)`以避免异常. (3认同)

Joe*_*ton 24

string myString = sourceString.Remove(sourceString.IndexOf(removeString),removeString.Length);
Run Code Online (Sandbox Code Playgroud)

编辑:@OregonGhost是对的.我自己会用条件来破坏脚本来检查这种情况,但是我假设字符串被某些要求赋予彼此属性.预计业务所需的异常处理规则可能会捕获这种可能性.我自己会使用一些额外的行来执行条件检查,并且对于那些可能没有花时间仔细阅读它的初级开发人员来说,它会更具可读性.

  • 如果sourceString中不包含removeString,则会崩溃. (8认同)

mal*_*ron 23

sourceString.Replace(removeString, "");
Run Code Online (Sandbox Code Playgroud)

  • [String.Replace](https://msdn.microsoft.com/en-us/library/fk49wtc1%28v=vs.110%29.aspx)说它"*[r] eturns一个新的字符串,其中所有出现当前实例中指定字符串的替换为另一个指定的字符串*".OP想要替换**第一次**事件. (14认同)
  • 此外,您应该解释一下您的答案,因为只有代码的答案是不可接受的.看看其他答案,并将它们与您的答案进行比较,以获得一些提示. (4认同)

Caf*_*eek 10

为此写了一个快速的TDD测试

    [TestMethod]
    public void Test()
    {
        var input = @"ProjectName\Iteration\Release1\Iteration1";
        var pattern = @"\\Iteration";

        var rgx = new Regex(pattern);
        var result = rgx.Replace(input, "", 1);

        Assert.IsTrue(result.Equals(@"ProjectName\Release1\Iteration1"));
    }
Run Code Online (Sandbox Code Playgroud)

rgx.Replace(input,"",1); 说要查看任何与模式匹配的输入,用"",1次.

  • 就像那样你解决了这个问题.在使用正则表达式解决此类问题时,请考虑性能. (2认同)

Dan*_*ipe 8

如果您想要一个简单的方法来解决这个问题。(可作为扩展使用)

见下文:

    public static string RemoveFirstInstanceOfString(this string value, string removeString)
    {
        int index = value.IndexOf(removeString, StringComparison.Ordinal);
        return index < 0 ? value : value.Remove(index, removeString.Length);
    }
Run Code Online (Sandbox Code Playgroud)

用法:

    string valueWithPipes = "| 1 | 2 | 3";
    string valueWithoutFirstpipe = valueWithPipes.RemoveFirstInstanceOfString("|");
    //Output, valueWithoutFirstpipe = " 1 | 2 | 3";
Run Code Online (Sandbox Code Playgroud)

受到@LukeH 和@Mike 答案的启发并修改。

不要忘记 StringComparison.Ordinal 以防止区域性设置出现问题。 https://www.jetbrains.com/help/resharper/2018.2/StringIndexOfIsCultureSpecific.1.html


Mik*_*nty 6

您可以使用扩展方法来获得乐趣.通常我不建议将扩展方法附加到像字符串这样的通用类,但就像我说这很有趣.我借用了@Luke的回答,因为没有必要重新发明轮子.

[Test]
public void Should_remove_first_occurrance_of_string() {

    var source = "ProjectName\\Iteration\\Release1\\Iteration1";

    Assert.That(
        source.RemoveFirst("\\Iteration"),
        Is.EqualTo("ProjectName\\Release1\\Iteration1"));
}

public static class StringExtensions {
    public static string RemoveFirst(this string source, string remove) {
        int index = source.IndexOf(remove);
        return (index < 0)
            ? source
            : source.Remove(index, remove.Length);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么通常不建议将扩展方法附加到像String这样的通用类?这有什么明显的缺点? (3认同)
  • 构建一个扩展方法的目的过于具体,以至于无法将其放在这样的通用类上,这是很容易的。例如,“IsValidIBAN(this string input)”过于具体,无法将其放在字符串上。 (3认同)