มีทางเลือกในการสตริงแทนที่ว่าเป็นกรณี ๆ ไปหรือไม่


306

ฉันต้องการค้นหาสตริงและแทนที่การเกิดทั้งหมด%FirstName%และ%PolicyAmount%ด้วยค่าที่ดึงออกมาจากฐานข้อมูล ปัญหาคือการใช้อักษรตัวพิมพ์ใหญ่ของ FirstName แตกต่างกันไป ที่ป้องกันฉันจากการใช้String.Replace()วิธีการ ฉันเคยเห็นหน้าเว็บในหัวข้อที่แนะนำ

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

อย่างไรก็ตามด้วยเหตุผลบางอย่างเมื่อฉันลองและแทนที่%PolicyAmount%ด้วย$0การแทนที่ไม่เคยเกิดขึ้น ฉันคิดว่ามันมีบางอย่างเกี่ยวกับเครื่องหมายดอลลาร์เป็นตัวละครที่สงวนไว้ใน regex

มีวิธีอื่นที่ฉันสามารถใช้ที่ไม่เกี่ยวข้องกับ sanitizing อินพุตเพื่อจัดการกับอักขระพิเศษ regex หรือไม่


1
หาก "$ 0" เป็นตัวแปรที่ดำเนินการอยู่ซึ่งจะไม่ส่งผลกระทบต่อ regex เลย
cfeduke

คำตอบ:


132

จาก MSDN
$ 0 - "ทดแทนซับสตริงสุดท้ายที่ตรงกับหมายเลขกลุ่ม (ทศนิยม)"

ใน. NET กลุ่มนิพจน์ปกติ 0 จะเป็นการจับคู่ทั้งหมดเสมอ สำหรับ $ อักษรที่คุณต้องการ

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

16
ในกรณีพิเศษนี้ใช้ได้ แต่ในกรณีที่มีการป้อนสตริงจากภายนอกเราไม่สามารถแน่ใจได้ว่าพวกเขาไม่มีอักขระที่หมายถึงบางสิ่งที่พิเศษในนิพจน์ทั่วไป
Allanrbo

23
คุณควรหลีกเลี่ยงอักขระพิเศษเช่นนี้: ค่าสตริง = Regex.Replace ("% PolicyAmount%", Regex.Escape ("% PolicyAmount%"), Regex.Escape ("$ 0"), RegexOptions.IgnoreCase);
Helge Klein

8
โปรดระวังเมื่อใช้ Regex.Escape ใน Regex.Replace คุณจะต้องหลบหนีจากทั้งสามสายที่ผ่านไปแล้วโทรหา Regex.Unescape ในผลลัพธ์!
Holger Adam

4
ตาม msdn: "การหลบหลีกตัวละครได้รับการยอมรับในรูปแบบการแสดงออกปกติ แต่ไม่ได้อยู่ในรูปแบบการแทนที่" ( msdn.microsoft.com/en-us/library/4edbef7e.aspx )
Bronek

1
วิธีที่ดีที่สุดคือใช้: ค่าสตริง = Regex.Replace ("% PolicyAmount%", Regex.Escape ("% PolicyAmount%"), "$ 0". แทนที่ ("$", "$$"), RegexOptions.IgnoreCase); เมื่อการแทนที่รับรู้สัญญาณ dolar เท่านั้น
Skorek

295

ดูเหมือนว่า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();
}

9
ดี ฉันจะเปลี่ยนไปReplaceString Replace
AMissico

41
เห็นด้วยกับความคิดเห็นข้างต้น สิ่งนี้สามารถทำให้เป็นวิธีการขยายที่มีชื่อวิธีการเดียวกัน เพียงปรากฏในคลาสแบบคงที่ด้วยลายเซ็นของเมธอด: สตริงแบบสแตติกสาธารณะแทนที่ (สตริงนี้ str, สตริงเก่าค่า, สตริงใหม่ค่า, เปรียบเทียบสตริงเปรียบเทียบ)
Mark Robinson

8
@Helge โดยทั่วไปอาจจะใช้ได้ แต่ฉันต้องใช้สตริงที่กำหนดเองจากผู้ใช้และไม่สามารถเสี่ยงอินพุตที่มีความหมายต่อ regex แน่นอนฉันเดาว่าฉันสามารถเขียนลูปและใส่แบ็กสแลชต่อหน้าตัวละครทุกตัว ... ณ จุดนั้นฉันอาจทำข้างบน (IMHO)
Jim

9
oldValue == newValue == ""ในขณะที่หน่วยทดสอบนี้ฉันวิ่งเข้าไปในกรณีที่จะไม่กลับมาเมื่อ
Ishmael

10
นี่คือรถม้าชนิดเล็ก; พ่นReplaceString("œ", "oe", "", StringComparison.InvariantCulture) ArgumentOutOfRangeException
Michael Liu

45

กลุ่มคำตอบที่สับสนส่วนหนึ่งเป็นเพราะชื่อของคำถามนั้นมากมีขนาดใหญ่กว่าคำถามเฉพาะที่ถูกถาม หลังจากอ่านผ่านไปฉันไม่แน่ใจว่าคำตอบใด ๆ ที่เป็นเพียงการแก้ไขเล็ก ๆ น้อย ๆ จากการดูดซึมสิ่งดีๆทั้งหมดที่นี่ดังนั้นฉันจึงคิดว่าฉันจะพยายามสรุป

ต่อไปนี้เป็นวิธีการขยายที่ฉันคิดว่าหลีกเลี่ยงข้อผิดพลาดที่กล่าวถึงที่นี่และนำเสนอโซลูชันที่ใช้งานได้อย่างกว้างขวางที่สุด

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 's ที่คุณต้องEscapeทั้งสามไม่ถูกต้อง ค่าเริ่มต้นและnewValueไม่จำเป็นต้องเป็น

หมายเหตุ:คุณไม่ แต่จะต้องหลบหนี$ในค่าใหม่ที่คุณใส่กำลังถ้าพวกเขาเป็นส่วนหนึ่งของสิ่งที่กำลังจะปรากฏเป็น "ค่าจับ" เครื่องหมาย ดังนั้นสัญญาณสามดอลลาร์ใน Regex แทนที่ภายใน Regex.Replace [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 ในการเข้ารหัส ) เพื่อให้แน่ใจว่าคุณได้รับสิ่งที่คุณ สำหรับกรณีการใช้งานที่สำคัญ เตือนฉันถึง Crockford ในเรื่อง " การแสดงออกปกติที่ไม่ปลอดภัย " เล็กน้อย บ่อยครั้งที่เราเขียน regexps ที่อนุญาตสิ่งที่เราต้องการ (ถ้าเราโชคดี) แต่ไม่ได้ตั้งใจให้เพิ่มเติมใน (เช่นคือ$10สตริงการจับค่า "ถูกต้อง" ใน regexp มูลค่าใหม่ของฉันข้างต้นหรือไม่) เพราะเราไม่ได้คิดมากพอ . ทั้งสองวิธีมีค่าและทั้งสองประเภทต่างสนับสนุนข้อผิดพลาดที่ไม่ได้ตั้งใจ มันมักจะง่ายที่จะดูถูกดูแคลนความซับซ้อน

การ$หลบหนีที่แปลก(และนั่นRegex.Escapeไม่ได้หลบหนีรูปแบบค่าที่ถูกจับอย่าง$0ที่ฉันคาดไว้ในการแทนที่ค่า) ทำให้ฉันโกรธไปพักหนึ่ง การเขียนโปรแกรมยาก (c) 1842


32

นี่คือวิธีการขยาย ไม่แน่ใจว่าฉันพบมันที่ไหน

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

}

คุณอาจต้องจัดการกรณีสตริงว่าง / null
Vad

2
ข้อผิดพลาดหลายอย่างในการแก้ปัญหานี้: 1. ตรวจสอบ originalString, oldValue และ newValue สำหรับ null 2. อย่าให้ orginalString ย้อนกลับ (ไม่ทำงานประเภทที่เรียบง่ายไม่ได้ผ่านการอ้างอิง) แต่กำหนดค่าของ orginalValue ก่อนกับสตริงใหม่และปรับเปลี่ยนและให้กลับมา
RWC

31

ดูเหมือนว่าวิธีที่ง่ายที่สุดคือใช้วิธีการแทนที่ที่มาพร้อมกับ. Net และมีมาตั้งแต่. Net 1.0:

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

เพื่อที่จะใช้วิธีนี้คุณต้องเพิ่มการอ้างอิงไปยัง Microsoft.VisualBasic แอสเซมบลี แอสเซมบลีนี้เป็นส่วนมาตรฐานของรันไทม์. Net จะไม่ดาวน์โหลดเพิ่มเติมหรือทำเครื่องหมายเป็นล้าสมัย


4
มันได้ผล. คุณต้องเพิ่มการอ้างอิงไปยังแอสเซมบลี Microsoft.VisualBasic
CleverPatrick

แปลกที่วิธีนี้มีปัญหาเมื่อฉันใช้ (ตัวอักษรที่จุดเริ่มต้นของบรรทัดหายไป) คำตอบที่ได้รับความนิยมสูงสุดจากที่นี่C. Dragon 76ทำงานอย่างที่คาดไว้
Jeremy Thompson

1
ปัญหานี้คือมันจะส่งกลับสตริงใหม่แม้ว่าจะไม่ได้ทำการแทนที่โดยที่ string.replace () ส่งกลับตัวชี้ไปยังสตริงเดียวกัน สามารถไม่มีประสิทธิภาพหากคุณทำอะไรบางอย่างเช่นจดหมายเวียน
Brain2000

4
Brain2000 คุณคิดผิด สตริงทั้งหมดใน. NET นั้นไม่เปลี่ยนรูป
Der_Meister

Der_Meister ในขณะที่สิ่งที่คุณพูดถูกต้อง แต่นั่นก็ไม่ได้ทำให้สิ่งที่ Brain2000 พูดผิด
Simon Hewitt

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

วิธีไหนดีกว่ากัน stackoverflow.com/a/244933/206730เกี่ยวกับอะไร ประสิทธิภาพที่ดีขึ้น?
Kiquenet

8

แรงบันดาลใจจากคำตอบของ cfeduke ฉันสร้างฟังก์ชันนี้ซึ่งใช้ IndexOf เพื่อค้นหาค่าเก่าในสตริงแล้วแทนที่ด้วยค่าใหม่ ฉันใช้สิ่งนี้ในการประมวลผลสคริปต์ SSIS หลายล้านแถวและวิธี regex นั้นช้ากว่านี้

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

+1 สำหรับไม่ใช้ regex เมื่อไม่จำเป็น แน่นอนว่าคุณใช้โค้ดอีกสองสามบรรทัด แต่มีประสิทธิภาพมากกว่าการแทนที่แบบอิง regex เว้นแต่ว่าคุณต้องการฟังก์ชัน $
ChrisG

6

ขยายคำตอบที่เป็นที่นิยมของ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();
     }
}

3

ตามคำตอบของ 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();
}

2

รุ่นที่คล้ายกับ C. Dragon แต่ถ้าคุณต้องการทดแทนเพียงครั้งเดียว:

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

1

นี่เป็นอีกตัวเลือกสำหรับการดำเนินการแทนที่ Regex เนื่องจากมีคนไม่มากนักที่สังเกตว่าการจับคู่นั้นมีตำแหน่งอยู่ภายในสตริง:

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

คุณช่วยอธิบายสาเหตุที่คุณคูณด้วย MatchNo ได้ไหม
Aheho

หากมีความยาวแตกต่างกันระหว่าง oldValue และ newValue สตริงจะยาวขึ้นหรือสั้นลงเมื่อคุณแทนที่ค่า match.Index หมายถึงตำแหน่งเดิมภายในสตริงเราจำเป็นต้องปรับเปลี่ยนตำแหน่งการเคลื่อนไหวเนื่องจากการแทนที่ของเรา อีกวิธีคือการดำเนินการลบ / แทรกจากขวาไปซ้าย
แบรนดอน

ฉันเข้าใจ. นั่นคือสิ่งที่ตัวแปร "offset" ใช้สำหรับ สิ่งที่ฉันไม่เข้าใจคือเหตุผลที่คุณคูณด้วยการจับคู่ไม่มี สัญชาตญาณของฉันบอกฉันว่าตำแหน่งของการแข่งขันภายในสตริงจะไม่มีความสัมพันธ์กับจำนวนจริงที่เกิดขึ้นก่อนหน้านี้
Aheho

ไม่เป็นไรฉันเข้าใจเลย การชดเชยจะต้องมีการปรับสัดส่วนตามจำนวนที่เกิดขึ้น หากคุณสูญเสียอักขระ 2 ตัวในแต่ละครั้งที่คุณจำเป็นต้องเปลี่ยนใหม่คุณจะต้องคำนึงถึงสิ่งนั้นเมื่อคำนวณพารามิเตอร์เป็นวิธีการลบ
Aheho

0
Regex.Replace(strInput, strToken.Replace("$", "[$]"), strReplaceWith, RegexOptions.IgnoreCase);

3
มันใช้งานไม่ได้ $ ไม่ได้อยู่ในโทเค็น มันอยู่ในสตริง StrReplace With
Aheho

9
และคุณไม่สามารถปรับให้เข้ากับมันได้?
Joel Coehoorn

18
ไซต์นี้ควรจะเป็นแหล่งเก็บข้อมูลสำหรับคำตอบที่ถูกต้อง ไม่ใช่คำตอบที่เกือบจะถูกต้อง
Aheho

0

วิธีการแสดงออกปกติควรทำงาน อย่างไรก็ตามสิ่งที่คุณสามารถทำได้คือตัวพิมพ์เล็กสตริงจากฐานข้อมูลตัวพิมพ์เล็ก% ตัวแปร% ที่คุณมีและจากนั้นค้นหาตำแหน่งและความยาวในสตริงที่ต่ำกว่าจากฐานข้อมูล โปรดจำไว้ว่าตำแหน่งในสตริงจะไม่เปลี่ยนเพียงเพราะกล่องที่ต่ำกว่า

จากนั้นใช้การวนซ้ำที่ย้อนกลับ (ง่ายกว่าถ้าคุณไม่ได้คุณจะต้องนับจำนวนการทำงานที่จุดต่อมาย้ายไป) ลบออกจากสตริงที่ไม่ใส่ตัวต่ำของคุณจากฐานข้อมูล% ตัวแปร% ตามตำแหน่งและ ความยาวและแทรกค่าการแทนที่


โดยการย้อนกลับฉันหมายถึงการประมวลผลตำแหน่งที่พบในการย้อนกลับจากที่ไกลที่สุดไปที่สั้นที่สุดไม่ได้ข้ามสตริงจากฐานข้อมูลในสิ่งที่ตรงกันข้าม
cfeduke

คุณทำได้หรือคุณอาจใช้ Regex :)
Ray

0

(เนื่องจากทุกคนกำลังถ่ายทำที่นี่) นี่คือเวอร์ชันของฉัน (พร้อมการตรวจสอบ 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");

0

ให้ฉันทำกรณีของฉันแล้วคุณสามารถฉีกฉันเป็นชิ้นเล็กชิ้นน้อยถ้าคุณต้องการ

Regex ไม่ใช่คำตอบสำหรับปัญหานี้ - ช้าเกินไปและหน่วยความจำกำลังหิว

StringBuilder ดีกว่า mangling สตริงมาก

เนื่องจากนี่จะเป็นวิธีส่วนขยายในการเสริมstring.Replaceผมเชื่อว่ามันสำคัญที่จะต้องจับคู่วิธีการทำงานดังนั้นการทิ้งข้อยกเว้นสำหรับปัญหาอาร์กิวเมนต์เดียวกันจึงมีความสำคัญเช่นเดียวกับการส่งคืนสตริงต้นฉบับหากไม่มีการแทนที่

ฉันเชื่อว่าการมีพารามิเตอร์ StringComparison ไม่ใช่ความคิดที่ดี ฉันลองแล้ว แต่กรณีทดสอบที่กล่าวถึงโดย michael-liu พบว่ามีปัญหา: -

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

ขณะที่ IndexOf จะจับคู่กันจะมีความไม่ตรงกันระหว่างความยาวของการจับคู่ในสตริงต้นทาง (1) และ oldValue.Length (2) สิ่งนี้ประจักษ์เองโดยทำให้ IndexOutOfRange ในโซลูชันอื่น ๆ เมื่อ oldValue.Length ถูกเพิ่มเข้ากับตำแหน่งการแข่งขันปัจจุบันและฉันไม่สามารถหาวิธีแก้ไขปัญหานี้ได้ Regex ไม่สามารถจับคู่เคสได้ดังนั้นฉันจึงใช้วิธีแก้ปัญหาอย่างจริงจังในการใช้StringComparison.OrdinalIgnoreCaseสำหรับโซลูชันของฉันเท่านั้น

รหัสของฉันคือคล้ายกับคำตอบอื่น ๆ StringBuilderแต่บิดของฉันเป็นที่ฉันมองหาการแข่งขันก่อนที่จะไปสู่ปัญหาของการสร้างที่ หากไม่พบสิ่งใดแสดงว่ามีการหลีกเลี่ยงการจัดสรรที่มีขนาดใหญ่ รหัสจะกลายเป็นdo{...}whileมากกว่าwhile{...}

ฉันได้ทำการทดสอบอย่างครอบคลุมกับ Answers อื่น ๆ และสิ่งนี้ออกมาเร็วกว่าเล็กน้อยและใช้หน่วยความจำน้อยลงเล็กน้อย

    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();
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.