I need to remove the first (and ONLY the first) occurrence of a string from another string.
Here is an example replacing the string "\\Iteration"
. This:
ProjectName\\Iteration\\Release1\\Iteration1
would become this:
ProjectName\\Release1\\Iteration1
Here some code that does this:
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;
That seems like 开发者_开发问答a lot of code.
So my question is this: Is there a cleaner/more readable/more concise way to do this?
int index = sourceString.IndexOf(removeString);
string cleanPath = (index < 0)
? sourceString
: sourceString.Remove(index, removeString.Length);
sourceString.Replace(removeString, "");
string myString = sourceString.Remove(sourceString.IndexOf(removeString),removeString.Length);
EDIT: @OregonGhost is right. I myself would break the script up with conditionals to check for such an occurence, but I was operating under the assumption that the strings were given to belong to each other by some requirement. It is possible that business-required exception handling rules are expected to catch this possibility. I myself would use a couple of extra lines to perform conditional checks and also to make it a little more readable for junior developers who may not take the time to read it thoroughly enough.
Wrote a quick TDD Test for this
[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"));
}
rgx.Replace(input, "", 1); says to look in input for anything matching the pattern, with "", 1 time.
You could use an extension method for fun. Typically I don't recommend attaching extension methods to such a general purpose class like string, but like I said this is fun. I borrowed @Luke's answer since there is no point in re-inventing the wheel.
[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);
}
}
If you'd like a simple method to resolve this problem. (Can be used as an extension)
See below:
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);
}
Usage:
string valueWithPipes = "| 1 | 2 | 3";
string valueWithoutFirstpipe = valueWithPipes.RemoveFirstInstanceOfString("|");
//Output, valueWithoutFirstpipe = " 1 | 2 | 3";
Inspired by and modified @LukeH's and @Mike's answer.
Don't forget the StringComparison.Ordinal to prevent issues with Culture settings. https://www.jetbrains.com/help/resharper/2018.2/StringIndexOfIsCultureSpecific.1.html
I definitely agree that this is perfect for an extension method, but I think it can be improved a bit.
public static string Remove(this string source, string remove, int firstN)
{
if(firstN <= 0 || string.IsNullOrEmpty(source) || string.IsNullOrEmpty(remove))
{
return source;
}
int index = source.IndexOf(remove);
return index < 0 ? source : source.Remove(index, remove.Length).Remove(remove, --firstN);
}
This does a bit of recursion which is always fun.
Here is a simple unit test as well:
[TestMethod()]
public void RemoveTwiceTest()
{
string source = "look up look up look it up";
string remove = "look";
int firstN = 2;
string expected = " up up look it up";
string actual;
actual = source.Remove(remove, firstN);
Assert.AreEqual(expected, actual);
}
精彩评论