[C#] 대소 문자를 구분하지 않는 문자열 대체 방법이 있습니까?

문자열을 검색하고 모든 발생 %FirstName%%PolicyAmount%데이터베이스에서 가져온 값으로 바꿔야 합니다. 문제는 FirstName의 대소 문자가 다양하다는 것입니다. 그 String.Replace()방법 을 사용하지 못하게합니다 . 제안하는 주제에 대한 웹 페이지를 보았습니다.

Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase);

그러나 나는 시도하고 대체 어떤 이유 %PolicyAmount%와 함께 $0, 교체는 발생하지 않았다. 달러 기호가 정규식에서 예약 된 문자와 관련이 있다고 가정합니다.

정규식 특수 문자를 처리하기 위해 입력을 살균하지 않는 다른 방법이 있습니까?



답변

MSDN
$ 0- “그룹 번호 번호 (10 진수)와 일치하는 마지막 하위 문자열을 대체합니다.”

.NET 정규식에서 그룹 0은 항상 전체 일치합니다. 리터럴 $의 경우

string value = Regex.Replace("%PolicyAmount%", "%PolicyAmount%", @"$$0", RegexOptions.IgnoreCase);


답변

처럼 보인다 string.Replace 해야 걸리는 과부하가 StringComparison인수를. 그렇지 않기 때문에 다음과 같이 시도 할 수 있습니다.

public static string ReplaceString(string str, string oldValue, string newValue, StringComparison comparison)
{
    StringBuilder sb = new StringBuilder();

    int previousIndex = 0;
    int index = str.IndexOf(oldValue, comparison);
    while (index != -1)
    {
        sb.Append(str.Substring(previousIndex, index - previousIndex));
        sb.Append(newValue);
        index += oldValue.Length;

        previousIndex = index;
        index = str.IndexOf(oldValue, index, comparison);
    }
    sb.Append(str.Substring(previousIndex));

    return sb.ToString();
}


답변

질문의 제목이 실제로 요청되는 특정 질문보다 훨씬 크기 때문에 혼란스러운 답변 그룹입니다 . 읽은 후, 나는 여기에 모든 좋은 것들을 동화시키는 것에 대한 몇 가지 편집 내용이 있는지 확실하지 않으므로 요약하려고합니다.

여기에 언급 된 함정을 피하고 가장 광범위하게 적용 가능한 솔루션을 제공하는 확장 방법이 있습니다.

public static string ReplaceCaseInsensitiveFind(this string str, string findMe,
    string newValue)
{
    return Regex.Replace(str,
        Regex.Escape(findMe),
        Regex.Replace(newValue, "\\$[0-9]+", @"$$$0"),
        RegexOptions.IgnoreCase);
}

그래서…

불행히도, 세 가지 모두에 대한 @HA의 의견 Escape은 정확하지 않습니다 . 초기 값이며 newValue반드시 그럴 필요는 없습니다.

참고 : 그러나 “포착 된 값”마커 인 것의 일부인 경우$ 삽입중인 새 값 에서을 이스케이프해야합니다 . 따라서 Regex.Replace [sic] 안에있는 Regex.Replace의 3 달러 기호. 그것 없이는 이와 같은 것이 깨집니다.

"This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")

오류는 다음과 같습니다.

An unhandled exception of type 'System.ArgumentException' occurred in System.dll

Additional information: parsing "The\hisr\ is\ he\HISr\ fork,\ he\hIsr\ spoon,\ he\hisrsssssss\ knife\." - Unrecognized escape sequence \h.

Regex에 익숙한 사람들은 사용이 오류를 피하는 것처럼 느껴지지만, 여전히 스니핑 문자열 (부분적 으로 인코딩에서 Spolsky 를 읽은 후에 만)에서 부분적으로 당신이 무엇을 얻는 지 확실히 알 수 있습니다. 중요한 사용 사례를위한 것입니다. Crockford가 ” 안전하지 않은 정규식 “에 대해 조금 생각 나게합니다 . 너무 자주 우리는 우리가 원하는 것을 허용하는 $10정규 표현식을 작성 하지만 (우리가 운이 좋으면) 의도하지 않게 더 많은 것을 허용합니다 (예를 들어 , 위의 newValue 정규 표현식에서 실제로 유효한 “캡처 값”문자열입니까?) . 두 방법 모두 가치가 있으며, 두 가지 방법 모두 서로 다른 유형의 의도하지 않은 오류를 권장합니다. 복잡성을 과소 평가하는 것은 종종 쉬운 일입니다.

그 이상한 $탈출 (그리고 대체 가치에서 예상했던 Regex.Escape것과 같은 캡처 된 가치 패턴을 피하지 못했습니다 $0)은 잠시 동안 나를 화나게했습니다. 프로그래밍이 어렵다 (C) 1842


답변

확장 방법은 다음과 같습니다. 어디서 찾았는지 모르겠습니다.

public static class StringExtensions
{
    public static string Replace(this string originalString, string oldValue, string newValue, StringComparison comparisonType)
    {
        int startIndex = 0;
        while (true)
        {
            startIndex = originalString.IndexOf(oldValue, startIndex, comparisonType);
            if (startIndex == -1)
                break;

            originalString = originalString.Substring(0, startIndex) + newValue + originalString.Substring(startIndex + oldValue.Length);

            startIndex += newValue.Length;
        }

        return originalString;
    }

}


답변

가장 쉬운 방법은 .Net과 함께 제공되며 .Net 1.0부터 사용 된 Replace 메서드를 사용하는 것입니다.

string res = Microsoft.VisualBasic.Strings.Replace(res, 
                                   "%PolicyAmount%", 
                                   "$0", 
                                   Compare: Microsoft.VisualBasic.CompareMethod.Text);

이 방법을 사용하려면 Microsoft.VisualBasic 어셈블리에 대한 참조를 추가해야합니다. 이 어셈블리는 .Net 런타임의 표준 부분으로, 추가 다운로드가 아니거나 더 이상 사용되지 않는 것으로 표시됩니다.


답변

    /// <summary>
    /// A case insenstive replace function.
    /// </summary>
    /// <param name="originalString">The string to examine.(HayStack)</param>
    /// <param name="oldValue">The value to replace.(Needle)</param>
    /// <param name="newValue">The new value to be inserted</param>
    /// <returns>A string</returns>
    public static string CaseInsenstiveReplace(string originalString, string oldValue, string newValue)
    {
        Regex regEx = new Regex(oldValue,
           RegexOptions.IgnoreCase | RegexOptions.Multiline);
        return regEx.Replace(originalString, newValue);
    }


답변

cfeduke의 답변에서 영감을 얻어 IndexOf를 사용하여 문자열에서 이전 값을 찾은 다음 새 값으로 대체하는이 함수를 만들었습니다. 나는 이것을 수백만 행을 처리하는 SSIS 스크립트에서 사용했으며 정규식 방법은 이것보다 느립니다.

public static string ReplaceCaseInsensitive(this string str, string oldValue, string newValue)
{
    int prevPos = 0;
    string retval = str;
    // find the first occurence of oldValue
    int pos = retval.IndexOf(oldValue, StringComparison.InvariantCultureIgnoreCase);

    while (pos > -1)
    {
        // remove oldValue from the string
        retval = retval.Remove(pos, oldValue.Length);

        // insert newValue in it's place
        retval = retval.Insert(pos, newValue);

        // check if oldValue is found further down
        prevPos = pos + newValue.Length;
        pos = retval.IndexOf(oldValue, prevPos, StringComparison.InvariantCultureIgnoreCase);
    }

    return retval;
}