ฉันมีสายนี้: ABCDEFGHIJ
ฉันต้องการแทนที่จากตำแหน่ง 4 ถึงตำแหน่ง 5 ด้วยสตริง ZX
มันจะมีลักษณะเช่นนี้: ABCZXFGHIJ
แต่ไม่ควรใช้กับstring.replace("DE","ZX")
- ฉันต้องใช้กับตำแหน่ง
ฉันจะทำมันได้อย่างไร
ฉันมีสายนี้: ABCDEFGHIJ
ฉันต้องการแทนที่จากตำแหน่ง 4 ถึงตำแหน่ง 5 ด้วยสตริง ZX
มันจะมีลักษณะเช่นนี้: ABCZXFGHIJ
แต่ไม่ควรใช้กับstring.replace("DE","ZX")
- ฉันต้องใช้กับตำแหน่ง
ฉันจะทำมันได้อย่างไร
คำตอบ:
StringBuilder
วิธีที่ง่ายที่สุดในการเพิ่มและลบช่วงในสตริงคือการใช้
var theString = "ABCDEFGHIJ";
var aStringBuilder = new StringBuilder(theString);
aStringBuilder.Remove(3, 2);
aStringBuilder.Insert(3, "ZX");
theString = aStringBuilder.ToString();
อีกทางเลือกหนึ่งคือใช้String.Substring
แต่ฉันคิดว่าStringBuilder
รหัสอ่านง่ายขึ้น
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");
นี่คือวิธีการขยายที่ไม่ได้ใช้ StringBuilder หรือซับสตริง วิธีนี้ยังช่วยให้สายอักขระการแทนที่ขยายผ่านความยาวของสายอักขระแหล่งที่มา
//// str - the source string
//// index- the start location to replace at (0-based)
//// length - the number of characters to be removed before inserting
//// replace - the string that is replacing characters
public static string ReplaceAt(this string str, int index, int length, string replace)
{
return str.Remove(index, Math.Min(length, str.Length - index))
.Insert(index, replace);
}
เมื่อใช้ฟังก์ชั่นนี้หากคุณต้องการให้สตริงการแทนที่ทั้งหมดแทนที่อักขระได้มากที่สุดให้ตั้งค่าความยาวเป็นความยาวของสตริงการแทนที่:
"0123456789".ReplaceAt(7, 5, "Hello") = "0123456Hello"
มิฉะนั้นคุณสามารถระบุจำนวนตัวอักษรที่จะถูกลบ:
"0123456789".ReplaceAt(2, 2, "Hello") = "01Hello456789"
หากคุณระบุความยาวเป็น 0 ฟังก์ชันนี้จะทำหน้าที่เหมือนกับฟังก์ชันแทรก:
"0123456789".ReplaceAt(4, 0, "Hello") = "0123Hello456789"
ฉันเดาว่านี่จะมีประสิทธิภาพมากกว่าเนื่องจากคลาส StringBuilder ไม่จำเป็นต้องเริ่มต้นและเนื่องจากใช้การดำเนินงานขั้นพื้นฐานมากขึ้น โปรดแก้ไขฉันหากฉันผิด :)
ใช้String.Substring()
(รายละเอียดที่นี่ ) เพื่อตัดส่วนที่เหลือแล้วเปลี่ยนของคุณจากนั้นส่วนที่ถูกต้อง เล่นกับดัชนีจนกว่าคุณจะเข้าใจถูกต้อง :)
สิ่งที่ต้องการ:
string replacement=original.Substring(0,start)+
rep+original.Substring(start+rep.Length);
เป็นวิธีการขยาย
public static class StringBuilderExtension
{
public static string SubsituteString(this string OriginalStr, int index, int length, string SubsituteStr)
{
return new StringBuilder(OriginalStr).Remove(index, length).Insert(index, SubsituteStr).ToString();
}
}
string s = "ABCDEFG";
string t = "st";
s = s.Remove(4, t.Length);
s = s.Insert(4, t);
t
กลับมาอีก
หากคุณใส่ใจกับประสิทธิภาพการทำงานสิ่งที่คุณต้องการหลีกเลี่ยงคือการจัดสรร และถ้าคุณอยู่ในสุทธิหลัก 2.1 + (หรือเป็นยังอาคิโอะสุทธิมาตรฐาน 2.1) จากนั้นคุณสามารถจะทำได้โดยใช้วิธีการ :string.Create
public static string ReplaceAt(this string str, int index, int length, string replace)
{
return string.Create(str.Length - length + replace.Length, (str, index, length, replace),
(span, state) =>
{
state.str.AsSpan().Slice(0, state.index).CopyTo(span);
state.replace.AsSpan().CopyTo(span.Slice(state.index));
state.str.AsSpan().Slice(state.index + state.length).CopyTo(span.Slice(state.index + state.replace.Length));
});
}
วิธีนี้ยากต่อการเข้าใจมากกว่าทางเลือก แต่เป็นวิธีเดียวที่จะจัดสรรวัตถุเดียวต่อการโทร: สตริงที่สร้างขึ้นใหม่
คุณสามารถลองลิงค์อะไรก็ได้:
string str = "ABCDEFGHIJ";
str = str.Substring(0, 2) + "ZX" + str.Substring(5);
เช่นเดียวกับคนอื่น ๆ ได้กล่าวถึงSubstring()
ฟังก์ชั่นจะมีเหตุผล:
static void Main(string[] args)
{
string input = "ABCDEFGHIJ";
string output = input.Overwrite(3, "ZX"); // 4th position has index 3
// ABCZXFGHIJ
}
public static string Overwrite(this string text, int position, string new_text)
{
return text.Substring(0, position) + new_text + text.Substring(position + new_text.Length);
}
อีกทั้งฉันยังจับเวลากับStringBuilder
วิธีแก้ปัญหาและรับ 900 ภาพเทียบกับ 875 ดังนั้นมันจึงช้ากว่าเล็กน้อย
"ABCDEFGHIJ"
และ"ZX"
มีความยาวแตกต่างกัน
อีกอย่างหนึ่ง
public static string ReplaceAtPosition(this string self, int position, string newValue)
{
return self.Remove(position, newValue.Length).Insert(position, newValue);
}
ด้วยความช่วยเหลือของโพสต์นี้ฉันสร้างฟังก์ชั่นต่อไปนี้ด้วยการตรวจสอบความยาวเพิ่มเติม
public string ReplaceStringByIndex(string original, string replaceWith, int replaceIndex)
{
if (original.Length >= (replaceIndex + replaceWith.Length))
{
StringBuilder rev = new StringBuilder(original);
rev.Remove(replaceIndex, replaceWith.Length);
rev.Insert(replaceIndex, replaceWith);
return rev.ToString();
}
else
{
throw new Exception("Wrong lengths for the operation");
}
}
คำตอบอื่น ๆ ทั้งหมดไม่ทำงานหากสตริงมี Unicode char (เช่น Emojis)เนื่องจาก Unicode char มีน้ำหนักมากกว่าไบต์มากกว่าถ่าน
ตัวอย่าง : อีโมจิ '🎶' ที่แปลงเป็นไบต์จะมีน้ำหนักเท่ากับ 2 ตัวอักษร ดังนั้นถ้าถ่าน Unicode วางอยู่ที่จุดเริ่มต้นของสตริง
offset
พารามิเตอร์จะเปลี่ยน)
ด้วยหัวข้อนี้ฉันขยายคลาส StringInfo เพื่อแทนที่โดยตำแหน่งที่รักษาอัลกอริทึมของ Nick Miller เพื่อหลีกเลี่ยงปัญหาดังกล่าว:
public static class StringInfoUtils
{
public static string ReplaceByPosition(this string str, string replaceBy, int offset, int count)
{
return new StringInfo(str).ReplaceByPosition(replaceBy, offset, count).String;
}
public static StringInfo ReplaceByPosition(this StringInfo str, string replaceBy, int offset, int count)
{
return str.RemoveByTextElements(offset, count).InsertByTextElements(offset, replaceBy);
}
public static StringInfo RemoveByTextElements(this StringInfo str, int offset, int count)
{
return new StringInfo(string.Concat(
str.SubstringByTextElements(0, offset),
offset + count < str.LengthInTextElements
? str.SubstringByTextElements(offset + count, str.LengthInTextElements - count - offset)
: ""
));
}
public static StringInfo InsertByTextElements(this StringInfo str, int offset, string insertStr)
{
if (string.IsNullOrEmpty(str?.String))
return new StringInfo(insertStr);
return new StringInfo(string.Concat(
str.SubstringByTextElements(0, offset),
insertStr,
str.LengthInTextElements - offset > 0 ? str.SubstringByTextElements(offset, str.LengthInTextElements - offset) : ""
));
}
}
ฉันกำลังมองหาวิธีแก้ปัญหาด้วยข้อกำหนดต่อไปนี้:
ทางออกที่ดีที่สุดสำหรับฉันคือ:
// replace `oldString[i]` with `c`
string newString = new StringBuilder(oldString).Replace(oldString[i], c, i, 1).ToString();
สิ่งนี้ใช้ StringBuilder.Replace(oldChar, newChar, position, count)
โซลูชันอื่นที่ตรงตามความต้องการของฉันคือใช้Substring
กับการต่อข้อมูล:
string newString = oldStr.Substring(0, i) + c + oldString.Substring(i+1, oldString.Length);
ก็โอเคเช่นกัน ฉันเดาว่ามันไม่ได้มีประสิทธิภาพเท่ากับการแสดงครั้งแรกที่ชาญฉลาด (เนื่องจากการต่อสตริงที่ไม่จำเป็น) แต่เพิ่มประสิทธิภาพก่อนกำหนดเป็นรากของความชั่วร้ายทั้งหมด
ดังนั้นเลือกอันที่คุณชอบมากที่สุด :)
String.substr()
มันจะดีกว่าที่จะใช้
แบบนี้:
ReplString = GivenStr.substr(0, PostostarRelStr)
+ GivenStr(PostostarRelStr, ReplString.lenght());
string myString = "ABCDEFGHIJ";
string modifiedString = new StringBuilder(myString){[3]='Z', [4]='X'}.ToString();
ให้ฉันอธิบายวิธีแก้ปัญหาของฉัน
ให้คำแถลงปัญหาของการแก้ไขสตริงในตำแหน่งเฉพาะสองตำแหน่ง (“ ตำแหน่ง 4 เป็นตำแหน่ง 5”) ด้วยอักขระสองตัว 'Z' และ 'X' และการถามคือการใช้ดัชนีตำแหน่งเพื่อเปลี่ยนสตริงและไม่ใช่สตริงแทนที่ ( ) วิธีการ (อาจเป็นเพราะความเป็นไปได้ของการซ้ำซ้อนของอักขระบางตัวในสตริงจริง) ฉันต้องการใช้วิธีการที่เรียบง่ายเพื่อให้บรรลุเป้าหมายมากกว่าการใช้Substring()
และสตริงConcat()
หรือสตริงRemove()
และInsert()
วิธีการ แม้ว่าการแก้ปัญหาทั้งหมดนั้นจะให้บริการวัตถุประสงค์ในการบรรลุเป้าหมายเดียวกัน แต่มันก็ขึ้นอยู่กับตัวเลือกส่วนบุคคลและปรัชญาของการตกตะกอนด้วยวิธีการที่เรียบง่าย
กลับมาที่วิธีการแก้ปัญหาของฉันที่กล่าวถึงข้างต้นถ้าเรามองใกล้string
และStringBuilder
ทั้งคู่จะใช้สตริงที่กำหนดเป็นอาร์เรย์ของอักขระภายใน ถ้าเราดูที่การนำไปปฏิบัติStringBuilder
มันเก็บรักษาตัวแปรภายในบางอย่างเช่น " internal char[] m_ChunkChars;
" เพื่อจับภาพสตริงที่กำหนด ตอนนี้เนื่องจากนี่เป็นตัวแปรภายในเราจึงไม่สามารถเข้าถึงได้โดยตรง สำหรับโลกภายนอกเพื่อให้สามารถเข้าถึงและแก้ไขอาเรย์ตัวละครนั้นStringBuilder
จะเปิดเผยผ่านคุณสมบัติตัวสร้างดัชนีซึ่งมีลักษณะดังนี้
[IndexerName("Chars")]
public char this[int index]
{
get
{
StringBuilder stringBuilder = this;
do
{
// … some code
return stringBuilder.m_ChunkChars[index1];
// … some more code
}
}
set
{
StringBuilder stringBuilder = this;
do
{
//… some code
stringBuilder.m_ChunkChars[index1] = value;
return;
// …. Some more code
}
}
}
โซลูชันของฉันที่กล่าวถึงข้างต้นใช้ประโยชน์จากความสามารถของตัวทำดัชนีนี้เพื่อปรับเปลี่ยนอาร์เรย์อักขระที่ดูแลรักษาภายในโดยตรงซึ่ง IMO นั้นมีประสิทธิภาพและเรียบง่าย
BTW; เราสามารถเขียนวิธีการแก้ปัญหาข้างต้นอย่างละเอียดมากขึ้นบางอย่างเช่นด้านล่าง
string myString = "ABCDEFGHIJ";
StringBuilder tempString = new StringBuilder(myString);
tempString[3] = 'Z';
tempString[4] = 'X';
string modifiedString = tempString.ToString();
ในบริบทนี้ยังต้องการที่จะพูดถึงว่าในกรณีที่string
มันยังมีคุณสมบัติตัวทำดัชนีเป็นวิธีการเปิดเผยอาร์เรย์ตัวละครภายในของมัน แต่ในกรณีนี้มันมีเพียงคุณสมบัติ Getter (และไม่มี Setter) เป็นสตริงที่ไม่เปลี่ยนรูปในธรรมชาติ และนั่นคือสาเหตุที่เราต้องใช้StringBuilder
เพื่อเปลี่ยนอาเรย์ตัวละคร
[IndexerName("Chars")]
public extern char this[int index] { [SecuritySafeCritical, __DynamicallyInvokable, MethodImpl(MethodImplOptions.InternalCall)] get; }
และสุดท้าย แต่ไม่ใช่อย่างน้อยโซลูชันนี้เหมาะที่สุดสำหรับปัญหาเฉพาะนี้โดยการถามคือการแทนที่อักขระเพียงไม่กี่ตัวด้วยดัชนีตำแหน่งที่ทราบล่วงหน้า มันอาจจะไม่เหมาะสมที่สุดเมื่อความต้องการคือการเปลี่ยนสตริงที่มีความยาวพอสมควรเช่นจำนวนตัวอักษรที่ต้องการเปลี่ยนมีจำนวนมาก
String timestamp = "2019-09-18 21.42.05.000705";
String sub1 = timestamp.substring(0, 19).replace('.', ':');
String sub2 = timestamp.substring(19, timestamp.length());
System.out.println("Original String "+ timestamp);
System.out.println("Replaced Value "+ sub1+sub2);
นี่คือวิธีการขยายอย่างง่าย:
public static class StringBuilderExtensions
{
public static StringBuilder Replace(this StringBuilder sb, int position, string newString)
=> sb.Replace(position, newString.Length, newString);
public static StringBuilder Replace(this StringBuilder sb, int position, int length, string newString)
=> (newString.Length <= length)
? sb.Remove(position, newString.Length).Insert(position, newString)
: sb.Remove(position, length).Insert(position, newString.Substring(0, length));
}
ใช้มันแบบนี้:
var theString = new string(' ', 10);
var sb = new StringBuilder(theString);
sb.Replace(5, "foo");
return sb.ToString();
ฉันเชื่อว่าวิธีที่ง่ายที่สุดคือ: (ไม่มีตัวสร้างสตริง)
string myString = "ABCDEFGHIJ";
char[] replacementChars = {'Z', 'X'};
byte j = 0;
for (byte i = 3; i <= 4; i++, j++)
{
myString = myString.Replace(myString[i], replacementChars[j]);
}
ใช้งานได้เพราะตัวแปรประเภทสตริงสามารถใช้เป็นอาร์เรย์ของตัวแปรถ่านได้ ตัวอย่างเช่นคุณสามารถอ้างถึงอักขระตัวที่สองของตัวแปรสตริงที่ชื่อ "myString" เป็น myString [1]
string
อักขระที่จะถูกแทนที่แต่ละตัวจะเกิดขึ้นเพียงครั้งเดียว หากคุณทำสิ่งนี้กับพูด"DBCDEFGHIE"
แล้วคุณจะได้รับ"ZBCZXFGHIX"
ซึ่งไม่ใช่ผลลัพธ์ที่ต้องการ นอกจากนี้ฉันจะไม่ยอมรับว่าสิ่งนี้ง่ายกว่าStringBuilder
โซลูชันอื่น ๆที่โพสต์เมื่อสองปีครึ่งที่แล้ว