다른 문자열에서 첫 번째 부분 문자열을 제거하는 가장 간단한 방법


87

다른 문자열에서 문자열의 첫 번째 (그리고 첫 번째 만) 발생을 제거해야합니다.

다음은 문자열을 대체하는 예 "\\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;

그것은 많은 코드처럼 보입니다.

그래서 내 질문은 이것입니다 : 이것을 수행하는 더 깨끗하고 / 더 읽기 쉽고, 더 간결한 방법이 있습니까?

답변:


152
int index = sourceString.IndexOf(removeString);
string cleanPath = (index < 0)
    ? sourceString
    : sourceString.Remove(index, removeString.Length);

10
이 대답은 ASCII가 아닌 문자를 포함하는 문자열에서 깨질 수 있습니다. 예를 들어, EN-US 배양 하에서 æae동일한 것으로 간주된다. 제거하기 paedia로하는 Encyclopædia가 발생합니다 ArgumentOutOfRangeException당신은 6 개 문자를 제거하기 때문에 단지 하위 문자열 일치 5. 포함 된 경우,
더글러스

6
sourceString.IndexOf(removeString, StringComparison.Ordinal)예외를 피하기 위해 다음 과 같이 수정할 수 있습니다 .
Borislav Ivanov

29
string myString = sourceString.Remove(sourceString.IndexOf(removeString),removeString.Length);

편집 : @OregonGhost가 맞습니다. 나는 그러한 발생을 확인하기 위해 조건부로 스크립트를 분해 할 것이지만, 어떤 요구 사항에 의해 문자열이 서로에게 속하도록 주어진다는 가정하에 작업하고있었습니다. 비즈니스에 필요한 예외 처리 규칙이 이러한 가능성을 포착 할 것으로 예상 될 수 있습니다. 필자는 몇 줄을 추가로 사용하여 조건부 검사를 수행하고 시간을 들여 충분히 읽지 못하는 주니어 개발자에게 좀 더 읽기 쉽게 만들었습니다.


9
removeString이 sourceString에 포함되지 않으면 충돌이 발생합니다.
OregonGhost

26
sourceString.Replace(removeString, "");

18
String.Replace 는 " [r] 현재 인스턴스에서 지정된 문자열의 모든 발생이 다른 지정된 문자열로 대체되는 새 문자열을 반환 한다고 말합니다 . OP는 첫 번째 발생 을 대체하려고했습니다 .
Wai Ha Lee

6
또한 코드 전용 답변은 허용되지 않으므로 답변을 약간 설명해야합니다. 다른 답변을 살펴보고 몇 가지 팁을 위해 귀하의 답변과 비교하십시오.
Wai Ha Lee

11

이에 대한 빠른 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"));
    }

rgx.Replace (input, "", 1); 입력에서 패턴과 일치하는 항목을 검색하라고 "", 1 번.


2
당신이 문제를 해결 한 것처럼. 이와 같은 문제에 정규식을 사용할 때 성능을 고려하십시오.
Thomas

7

재미를 위해 확장 방법 을 사용할 수 있습니다 . 일반적으로 문자열과 같은 범용 클래스에 확장 메서드를 연결하지 않는 것이 좋지만 이것이 재미 있다고 말했듯이. 바퀴를 재발 명 할 필요가 없기 때문에 @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);
    }
}

3
일반적으로 String과 같은 범용 클래스에 확장 메서드를 연결하지 않는 것이 좋습니다. 이것에 어떤 명백한 단점이 있습니까?
Teun Kooijman

1
이러한 범용 클래스에 적용하기에는 너무 특정한 목적을위한 확장 메서드를 빌드하는 것은 쉽습니다. 예를 들어, IsValidIBAN(this string input)문자열에 포함하기에는 너무 구체적입니다.
Squirrelkiller

3

이 문제를 해결하는 간단한 방법을 원할 경우. (확장자로 사용 가능)

아래를 참조하십시오.

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

용법:

    string valueWithPipes = "| 1 | 2 | 3";
    string valueWithoutFirstpipe = valueWithPipes.RemoveFirstInstanceOfString("|");
    //Output, valueWithoutFirstpipe = " 1 | 2 | 3";

@LukeH 및 @Mike의 답변에서 영감을 얻고 수정했습니다.

Culture 설정 문제를 방지하려면 StringComparison.Ordinal을 잊지 마세요. https://www.jetbrains.com/help/resharper/2018.2/StringIndexOfIsCultureSpecific.1.html


2

나는 이것이 확장 방법에 완벽하다는 데 확실히 동의하지만 조금 개선 될 수 있다고 생각합니다.

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

이것은 항상 재미있는 약간의 재귀를 수행합니다.

다음은 간단한 단위 테스트입니다.

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

    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.