स्थिति द्वारा स्ट्रिंग के भाग को कैसे बदला जाए?


155

मेरे पास यह स्ट्रिंग है: ABCDEFGHIJ

मुझे स्ट्रिंग से स्थिति 4 से स्थिति 5 तक बदलने की आवश्यकता है ZX

यह इस तरह दिखेगा: ABCZXFGHIJ

लेकिन उपयोग करने के लिए नहीं string.replace("DE","ZX")- मुझे स्थिति के साथ उपयोग करने की आवश्यकता है

मैं यह कैसे कर सकता हूं?


@ टोटज़म - कृपया तारीखों की जाँच करें। यह एक आपके द्वारा लिंक किए गए से पुराना है।
टूलमेकरसेव

@ToolmakerSteve मैं आमतौर पर प्रश्नों और उत्तरों की गुणवत्ता को देखता हूं, तिथियों को नहीं, जैसा कि यहां कहा गया है । इस मामले में, मुझे लगता है कि एक गलती हुई है और एक गलत को नकली के रूप में चिह्नित करने के लिए क्लिक किया है, क्योंकि इस प्रश्न की गुणवत्ता स्पष्ट रूप से बेहतर है, और इसलिए मैंने दूसरे प्रश्न को चिह्नित किया है।
टॉट ज़म

@TZZam - आह, मुझे उस सिफारिश के बारे में नहीं पता था - इसे इंगित करने के लिए धन्यवाद। (हालांकि यह कुछ पुराने रिपोर्ट किए गए कुछ नए की नकल के रूप में देखने के लिए भ्रमित है, इसलिए इस तरह के मामले में, यह स्पष्ट रूप से समझाने योग्य होगा कि आप एक OLDER प्रश्न के रूप में चिह्नित कर रहे हैं, क्योंकि लिंक वाले के पास बेहतर उत्तर हैं।)
टूलमेकरसैटवे

जवाबों:


198

एक स्ट्रिंग में श्रेणियों को जोड़ने और हटाने का सबसे आसान तरीका है StringBuilder

var theString = "ABCDEFGHIJ";
var aStringBuilder = new StringBuilder(theString);
aStringBuilder.Remove(3, 2);
aStringBuilder.Insert(3, "ZX");
theString = aStringBuilder.ToString();

एक विकल्प का उपयोग करना है String.Substring, लेकिन मुझे लगता है कि StringBuilderकोड अधिक पठनीय हो जाता है।


6
बेहतर होगा कि एक विस्तार विधि में रैपिंग :)
balexandre

आप यहां स्ट्रिंगबुक का उपयोग क्यों करते हैं? V4Vendetta के उत्तर की जाँच करें, जो बहुत अधिक पठनीय है ...
Fortega

1
@ फ़ोर्टगेगा निकालें () और डालें () प्रत्येक बनाएँ और एक नया स्ट्रिंग लौटें। StringBuilder दृष्टिकोण स्मृति के एक पूर्व-आवंटित खंड के भीतर काम करके और इसके भीतर चारो तरफ घूमकर इस अतिरिक्त लागत से बचता है।
redcalx

@redcalx यह सच है, लेकिन एक अतिरिक्त लागत एक StringBuilder वस्तु शुरू करने और पठनीयता को कम करने से शुरू की है
Fortega

2
StringBuilder का उपयोग करने का क्या मतलब है, अगर आप V4Vendetta के समान तरीके से निकालें और सम्मिलित कर रहे हैं, लेकिन वह सीधे स्ट्रिंग पर कर रहा है? बेमानी कोड लगता है।
मेटाबड्डी

186
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");

17
मैं इस पर एक नया StringBuilder (...) को शुरू करने को प्राथमिकता देता हूं। धन्यवाद!
माइकल नॉरग्रेन

3
मुझे नहीं पता कि कोई इस ऑपरेशन के लिए स्ट्रिंगर का इस्तेमाल क्यों करेगा। यह अच्छा जवाब है
NappingRabbit

43

रिप्लेसमेंट (इंट इंडेक्स, इंट लेंथ, स्ट्रिंग रिप्लेस)

यहाँ एक विस्तार विधि है जो 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 वर्ग को शुरू करने की आवश्यकता नहीं है और चूंकि यह अधिक बुनियादी संचालन का उपयोग करता है। अगर मैं गलत हूं कृपया मुझे सही। :)


5
स्ट्रिंगर की तुलना में अधिक कुशल है यदि स्ट्रिंग 200 से अधिक है, तो 200 अक्षर कहें।
टिम श्मेल्टर

कोई तनाव नहीं है। सीधे काम किया। धन्यवाद
D_Edet

9

बाएं हिस्से को काटने के लिए String.Substring()( यहां विवरण ) का उपयोग करें , फिर आपका प्रतिस्थापन, फिर दायां भाग। जब तक आप इसे सही नहीं करते तब तक अनुक्रमित के साथ खेलें :)

कुछ इस तरह:

string replacement=original.Substring(0,start)+
    rep+original.Substring(start+rep.Length);

2
मैंने उपरोक्त तीन विधियों (string.Remove / Insert, Stringbuilder.Remove / Insert और Daniel's Substring उत्तर) का उपयोग करके तीन विधियाँ बनाईं और सबस्ट्रिंग सबसे तेज़ विधि थी।
फ्रेंकिन डेग्रोड टेलर

7

एक विस्तार विधि के रूप में।

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


4

यदि आप प्रदर्शन के बारे में परवाह करते हैं, तो आप जिस चीज से बचना चाहते हैं, वह है आवंटन। और अगर आप नेट कोर 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));
        });
}

यह दृष्टिकोण विकल्पों की तुलना में समझना कठिन है, लेकिन यह केवल एक ही है जो प्रति कॉल केवल एक वस्तु आवंटित करेगा: नव निर्मित स्ट्रिंग।


3

आप इसे लिंक करने का प्रयास कर सकते हैं:

string str = "ABCDEFGHIJ";
str = str.Substring(0, 2) + "ZX" + str.Substring(5);

3

जैसे अन्य ने उल्लेख किया है कि 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 tics बनाम 875 प्राप्त किया। इसलिए यह थोड़ा धीमा है।


@ हारून। - नहीं यह नहीं है। मेरे उदाहरण में "ABCDEFGHIJ"और "ZX"अलग-अलग लंबाई के हैं।
जॉन एलेक्सी

3

अभी तक एक और

    public static string ReplaceAtPosition(this string self, int position, string newValue)        
    {
        return self.Remove(position, newValue.Length).Insert(position, newValue); 
    }

2

इस पोस्ट की मदद से, मैं अतिरिक्त लंबाई की जांच के साथ निम्नलिखित फ़ंक्शन बनाता हूं

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

2

अन्य सभी उत्तर काम नहीं करते हैं यदि स्ट्रिंग में यूनिकोड चार (जैसे इमोजीस) हो, क्योंकि एक यूनिकोड चार वजन एक चार से अधिक बाइट करता है।

उदाहरण : इमोजी 'converted' बाइट्स में परिवर्तित, 2 वर्णों के बराबर वजन करेगा। इसलिए, यदि यूनिकोड चार को आपकी स्ट्रिंग की शुरुआत में रखा गया है, तो offsetपैरामीटर को स्थानांतरित कर दिया जाएगा)।

इस विषय के साथ , मैं StringInfo क्लास का विस्तार करने के लिए निक मिलर के एल्गोरिथ्म से बचने के लिए स्थिति से प्रतिस्थापित कर सकता हूं:

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

dotnetfiddle.net/l0dqS5 मुझे यूनिकोड पर विफल होने के लिए अन्य तरीके नहीं मिल सके। कृपया अपने उपयोग के मामले को प्रदर्शित करने के लिए फिडल को बदल दें। बहुत रुचि, परिणामों में।
मार्कस

1
@MarkusHooge अपने स्ट्रिंग की शुरुआत में यूनिकोड वर्णों को रखने का प्रयास करें जैसे: dotnetfiddle.net/3V2K3Y । आप केवल अंतिम पंक्ति को अच्छी तरह से काम करते हुए देखेंगे और 4 वें स्थान पर चार को जगह देंगे (दूसरे मामले में, यूनिकोड चार की लंबाई 2
चार्ट है

आप सही हैं, यह स्पष्ट नहीं है। मैंने अपने स्पष्टीकरण को और स्पष्टीकरण देने के लिए अद्यतन किया कि क्यों अन्य उत्तर काम नहीं करते हैं
GGO

1

मैं निम्नलिखित आवश्यकताओं के साथ एक समाधान की तलाश में था:

  1. केवल एक एकल, एक-पंक्ति अभिव्यक्ति का उपयोग करें
  2. केवल सिस्टम बिलिन विधियों का उपयोग करें (कोई कस्टम कार्यान्वित उपयोगिता नहीं)

समाधान 1

समाधान है कि सबसे अच्छा मुझे यह है:

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

यह ठीक भी है। मुझे लगता है कि यह पहले प्रदर्शन के लिहाज से उतना कुशल नहीं है (अनावश्यक स्ट्रिंग के कारण)। लेकिन समयपूर्व अनुकूलन सभी बुराई की जड़ है

तो एक है कि आप सबसे अधिक पसंद उठाओ :)


समाधान 2 काम करता है, लेकिन सुधार की आवश्यकता है: स्ट्रिंग newString = oldStr.Substring (0, i) + c + oldString.Substring (i + 1, oldString.Length- (i + 1));
यूरा जी

0

इसका उपयोग करना बेहतर है String.substr()

ऐशे ही:

ReplString = GivenStr.substr(0, PostostarRelStr)
           + GivenStr(PostostarRelStr, ReplString.lenght());

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

ऊपर दिए गए मेरे समाधान ने इस अनुक्रमणिका क्षमता का लाभ उठाया कि आंतरिक रूप से बनाए रखा चरित्र सरणी को बदलने के लिए जो आईएमओ कुशल और न्यूनतम है।

BTW; हम उपरोक्त समाधान को फिर से नीचे की तरह अधिक विस्तृत रूप से लिख सकते हैं

 string myString = "ABCDEFGHIJ";
 StringBuilder tempString = new StringBuilder(myString);
 tempString[3] = 'Z';
 tempString[4] = 'X';
 string modifiedString = tempString.ToString();

इस संदर्भ में यह भी उल्लेख करना चाहते हैं कि इसके मामले में stringइसके आंतरिक चरित्र सरणी को उजागर करने के साधन के रूप में भी अनुक्रमणिका संपत्ति है, लेकिन इस मामले में इसके पास केवल गेट्टर संपत्ति (और कोई सेटर) नहीं है क्योंकि स्ट्रिंग प्रकृति में अपरिवर्तनीय है। और यही कारण है कि हमें StringBuilderचरित्र सरणी को बदलने के लिए उपयोग करने की आवश्यकता है।

[IndexerName("Chars")]
public extern char this[int index] { [SecuritySafeCritical, __DynamicallyInvokable, MethodImpl(MethodImplOptions.InternalCall)] get; }

और अंतिम लेकिन कम से कम नहीं यह समाधान केवल इस विशिष्ट समस्या के लिए सबसे उपयुक्त है जहां पूछना केवल कुछ पात्रों को एक ज्ञात स्थिति इंडेक्स अपफ्रंट के साथ बदलना है। यह सबसे अच्छा फिट नहीं हो सकता है जब आवश्यकता एक काफी लंबी स्ट्रिंग को बदलने के लिए है यानी वर्णों की संख्या को बदलने के लिए संख्या में बड़ी हैं।


1
कृपया अपने उत्तर को यह समझाने के लिए संपादित करें कि यह कोड प्रश्न का उत्तर कैसे देता है
tshimkus

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

0

यहाँ एक सरल विस्तार विधि है:

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

-2

मेरा मानना ​​है कि सबसे सरल तरीका यह होगा: (स्ट्रिंगर के बिना)

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 [1] के रूप में "myString" नाम के साथ एक स्ट्रिंग चर के दूसरे चरित्र को संदर्भित कर सकते हैं।


यह केवल इसलिए काम करता है क्योंकि लेखक के उदाहरण stringमें प्रत्येक को प्रतिस्थापित करने वाले वर्ण केवल एक बार होते हैं। यदि आप इस के खिलाफ चलाते हैं, कहते हैं, "DBCDEFGHIE"तो आप प्राप्त करते हैं "ZBCZXFGHIX", जो वांछित परिणाम नहीं है। इसके अलावा, मैं यह नहीं मानूंगा कि यह StringBuilderढाई साल पहले पोस्ट किए गए अन्य गैर- समाधानों की तुलना में सरल है ।
बेकन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.