programing

스트링의 대안은 있습니까?대소문자를 구분하지 않는 대체품?

javajsp 2023. 4. 19. 22:14

스트링의 대안은 있습니까?대소문자를 구분하지 않는 대체품?

하여 모든 해야 합니다.%FirstName% ★★★★★★★★★★★★★★★★★」%PolicyAmount%값을 데이터베이스에서 가져옵니다.퍼스트 네임는 I/O를 사용할 수 .String.Replace()는 그 를 본 있다

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

, 어떤 로, 「」를 치환하려고 하면, 「」가 .%PolicyAmount%$0대체는 행해지지 않습니다.나는 그것이 정규식에서의 달러 기호가 예약 문자인 것과 관련이 있다고 생각한다.

regex 특수문자를 처리하기 위해 입력을 삭제하지 않고 사용할 수 있는 다른 방법이 있습니까?

것 같다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();
}


0달러 - "10달러입니다."

.NET에서는 정규 표현 그룹0 이 항상 일치합니다.문자 그대로의 달러라면

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

다소 혼란스러운 답변 그룹입니다.일부적으로는 질문의 제목이 실제로 질문의 구체적인 질문보다 훨씬 더 크기 때문입니다.읽어본 결과, 여기 있는 모든 좋은 것들을 이해하는 데 몇 가지 편집이 필요한 것 같기 때문에 요약해 보려고 했습니다.

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

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

그래서...

  • 확장 메서드 @MarkRobinson 입니다.
  • 이것은 Regex @Helge를 건너뛸 수 없습니다(Regex 외부에서 이와 같은 문자열 스니프를 수행하려면 바이트 단위로 수행해야 합니다).
  • @MichaelLiu의 우수한 테스트 케이스에 합격했습니다."œ".ReplaceCaseInsensitiveFind("oe", "")조금 다른 행동을 염두에 뒀을 수도 있지만요

유감스럽게도, @HA의 코멘트는, 이 세 가지 모두에 대응하고 있지 않습니다.초기값과newValue그럴 필요 없어

주의: 단, 탈출해야 합니다.$s는 삽입할 새 값에 포함되며, 이 값이 "최소값" 마커로 표시될 수 있습니다.따라서 정규판에는 3달러가 표시된다.Regex 내부를 교환합니다.[sic]을 바꿉니다.그게 없으면 이런 게 고장나면...

"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를 읽고 나서야 바이트 스니핑 스트링을 선호하는 경우가 많습니다."불안전한 정규 표현"의 크로크포드가 생각나네요우리가 원하는 것을 (운이 좋은 경우) 허용하지만 의도하지 않게 더 많은 것을 허용한다(예:$10 newValue ?)에 value"my newValue regexp는 "value value"를 "value value"로 입니다. 충분히 배려하지 않았기 때문입니다.두 방법 모두 가치가 있으며, 두 방법 모두 다른 유형의 의도하지 않은 오류를 유발합니다.복잡성을 과소평가하는 것은 종종 쉽습니다.

이상한 ★★★★★★★★★★★★★★★★★★★★★★★」$은)Regex.Escape''는 ''는'$0내가 대체값으로 예상한 대로) 한동안 날 화나게 했어.은 어렵다 1842년

에 부속되어 있는 Replace 방식을 사용하는 것이 가장 쉬운 방법인 것 같습니다.인터넷 및 그 이후부터 존재해 왔습니다.Net 1.0:

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

이 방법을 사용하려면 Microsoft에 참조를 추가해야 합니다.Visual Basic 어셈블리이 어셈블리는 의 표준 부품입니다.넷 런타임. 추가 다운로드가 아니거나 사용되지 않는 것으로 표시됩니다.

여기 연장 방법이 있습니다.어디서 찾았는지 모르겠어요.

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

}
    /// <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 스크립트에서 이것을 사용했는데 regex-method가 이것보다 훨씬 느렸습니다.

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

C로 확장됩니다. Dragon 76의 코드를 디폴트 오버로드 확장자로 만들어 인기 있는 답변Replace★★★★★★ 。

public static class StringExtensions
{
    public static string Replace(this 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();
     }
}

.NET Core 2.0 또는 이후.NET Standard 2.1은 각각에 포함되어 있습니다.NET 런타임 [1]:

"hello world".Replace("World", "csharp", StringComparison.CurrentCultureIgnoreCase); // "hello csharp"

[1] https://learn.microsoft.com/en-us/dotnet/api/system.string.replace#System_String_Replace_System_String_System_String_System_StringComparison_

Jeff Reddy의 답변을 바탕으로 다음과 같은 최적화와 검증을 실시합니다.

public static string Replace(string str, string oldValue, string newValue, StringComparison comparison)
{
    if (oldValue == null)
        throw new ArgumentNullException("oldValue");
    if (oldValue.Length == 0)
        throw new ArgumentException("String cannot be of zero length.", "oldValue");

    StringBuilder sb = null;

    int startIndex = 0;
    int foundIndex = str.IndexOf(oldValue, comparison);
    while (foundIndex != -1)
    {
        if (sb == null)
            sb = new StringBuilder(str.Length + (newValue != null ? Math.Max(0, 5 * (newValue.Length - oldValue.Length)) : 0));
        sb.Append(str, startIndex, foundIndex - startIndex);
        sb.Append(newValue);

        startIndex = foundIndex + oldValue.Length;
        foundIndex = str.IndexOf(oldValue, startIndex, comparison);
    }

    if (startIndex == 0)
        return str;
    sb.Append(str, startIndex, str.Length - startIndex);
    return sb.ToString();
}

C와 유사한 버전입니다.Dragon's, 단 한 가지 교체품만 필요한 경우:

int n = myText.IndexOf(oldValue, System.StringComparison.InvariantCultureIgnoreCase);
if (n >= 0)
{
    myText = myText.Substring(0, n)
        + newValue
        + myText.Substring(n + oldValue.Length);
}

다음은 정규식 치환을 실행하기 위한 다른 옵션입니다.이는 일치에 문자열 내의 위치가 포함되어 있는 것을 알아차리는 사용자가 많지 않기 때문입니다.

    public static string ReplaceCaseInsensative( this string s, string oldValue, string newValue ) {
        var sb = new StringBuilder(s);
        int offset = oldValue.Length - newValue.Length;
        int matchNo = 0;
        foreach (Match match in Regex.Matches(s, Regex.Escape(oldValue), RegexOptions.IgnoreCase))
        {
            sb.Remove(match.Index - (offset * matchNo), match.Length).Insert(match.Index - (offset * matchNo), newValue);
            matchNo++;
        }
        return sb.ToString();
    }

내가 내 주장을 펴고 네가 원한다면 날 갈기갈기 찢어버려도 돼

Regex는 이 문제에 대한 해답이 아닙니다.상대적으로 말하면 너무 느리고 메모리 부족입니다.

String Builder는 문자열 망글링보다 훨씬 좋습니다.

이 될 입니다.string.Replace그것이 어떻게 동작하는지가 중요하다고 생각합니다.따라서 교환이 이루어지지 않았을 때 원래의 문자열을 반환하는 것과 같은 논거에 예외를 두는 것이 중요합니다.

StringComparison 파라미터가 있는 것은 좋지 않다고 생각합니다.시험해 보았지만, 원래 michael-liu가 말한 테스트 케이스에서 문제가 발생했습니다.

[TestCase("œ", "oe", "", StringComparison.InvariantCultureIgnoreCase, Result = "")]

Index Of index 、 old Value ( 1 ) 。( (2) 이는oldValue에 다른 를 발생시킴으로써 .old Value 른른른른른 른른 、 Index Out Of Range 를outvalue 。현재 매치 포지션에 길이가 추가되어, 이 문제를 회피할 방법을 찾을 수 없었습니다.하지 않기 에 저는 "Regex"를 "Regex"로만 했습니다.StringComparison.OrdinalIgnoreCase내 해결책에 대해서.

, 은 '일치하다', '일치하다', '일치하다', '일치하다'를입니다.StringBuilder 아무것도 발견되지 않으면 큰 할당은 회피됩니다. 코드가 '아까운데'가 됩니다.do{...}while가 a a while{...}

다른 Answer와 비교해서 몇 가지 광범위한 테스트를 실시했습니다만, 이 테스트의 실행 속도는 다소 빨라져 메모리 사용량이 약간 감소했습니다.

    public static string ReplaceCaseInsensitive(this string str, string oldValue, string newValue)
    {
        if (str == null) throw new ArgumentNullException(nameof(str));
        if (oldValue == null) throw new ArgumentNullException(nameof(oldValue));
        if (oldValue.Length == 0) throw new ArgumentException("String cannot be of zero length.", nameof(oldValue));

        var position = str.IndexOf(oldValue, 0, StringComparison.OrdinalIgnoreCase);
        if (position == -1) return str;

        var sb = new StringBuilder(str.Length);

        var lastPosition = 0;

        do
        {
            sb.Append(str, lastPosition, position - lastPosition);

            sb.Append(newValue);

        } while ((position = str.IndexOf(oldValue, lastPosition = position + oldValue.Length, StringComparison.OrdinalIgnoreCase)) != -1);

        sb.Append(str, lastPosition, str.Length - lastPosition);

        return sb.ToString();
    }
Regex.Replace(strInput, strToken.Replace("$", "[$]"), strReplaceWith, RegexOptions.IgnoreCase);

정규 표현 방식이 작동해야 합니다.단, 데이터베이스의 문자열이 소문자로 표시되고 %variable%가 소문자로 표시되고 데이터베이스에서 캐시된 문자열의 위치와 길이를 찾을 수도 있습니다.스트링의 위치는 케이스가 낮다고 해서 바뀌지 않습니다.

그런 다음 역방향으로 이동하는 루프를 사용하면(그렇게 하지 않으면 나중에 포인트가 이동하는 곳의 실행 카운트를 유지할 필요가 있습니다), 데이터베이스에서 %variable%를 위치 및 길이별로 제거하고 치환값을 삽입합니다.

(모두가 도전하고 있기 때문에)다음은 마이버전입니다(null 체크, 올바른 입력 및 교환 이스케이프 포함)** 인터넷 및 기타 버전에서 영감을 얻음:

using System;
using System.Text.RegularExpressions;

public static class MyExtensions {
    public static string ReplaceIgnoreCase(this string search, string find, string replace) {
        return Regex.Replace(search ?? "", Regex.Escape(find ?? ""), (replace ?? "").Replace("$", "$$"), RegexOptions.IgnoreCase);          
    }
}

사용방법:

var result = "This is a test".ReplaceIgnoreCase("IS", "was");

언급URL : https://stackoverflow.com/questions/244531/is-there-an-alternative-to-string-replace-that-is-case-insensitive