문자열의 일부를 위치로 바꾸는 방법은 무엇입니까?


158

이 문자열이 있습니다. ABCDEFGHIJ

4 번 위치에서 5 번 위치로 바꿔야합니다. ZX

다음과 같이 표시됩니다. ABCZXFGHIJ

하지만 함께 사용하지 마십시오 string.replace("DE","ZX")-나는 위치 와 함께 사용해야합니다

어떻게하니?


@TotZam-날짜를 확인하세요. 이것은 당신이 연결 한 것보다 오래되었습니다.
ToolmakerSteve

@ToolmakerSteve 여기서 말한대로 날짜가 아닌 질문과 답변의 품질을 확인합니다 . 이 경우이 질문의 품질이 분명히 더 좋기 때문에 실수를 저질렀 고 잘못된 질문을 클릭하여 중복으로 표시 한 것 같습니다. 그래서 다른 질문에 플래그를 지정했습니다.
Tot Zam

@TotZam-아, 그 추천에 대해 몰랐습니다. 지적 해 주셔서 감사합니다. (오래된 항목이 새로운 항목의 중복으로보고 된 것을 보는 것은 혼란 스럽지만,이 경우 연결된 항목이 더 나은 답변을 제공하기 때문에 OLDER 질문을 중복으로 표시하고 있음을 명시 적으로 설명 할 가치가 있습니다.)
ToolmakerSteve

답변:


201

문자열에서 범위를 추가하고 제거하는 가장 쉬운 방법은 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

2
여기서 StringBuilder를 사용하는 이유는 무엇입니까? 더 많은 읽을 수 V4Vendetta의 대답 ... 확인
Fortega

2
@Fortega Remove () 및 Insert ()는 각각 새 문자열을 만들고 반환합니다. StringBuilder 접근 방식은 미리 할당 된 메모리 섹션 내에서 작업하고 그 안에서 문자를 이동하여 이러한 추가 비용을 방지합니다.
redcalx

@redcalx 맞습니다.하지만 StringBuilder 객체를 도입하고 가독성을 줄임으로써 추가 비용이 발생합니다
Fortega 2018

2
제거 및 삽입을 V4Vendetta와 같은 방식으로 호출하지만 문자열에서 직접 수행하는 경우 StringBuilder를 사용하는 이유는 무엇입니까? 중복 코드 인 것 같습니다.
metabuddy

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

19
새로운 StringBuilder (...)를 초기화하는 것보다 이것을 선호합니다. 감사!
Michael Norgren 2014 년

3
누군가이 작업에 stringbuilder를 사용하는 이유를 모르겠습니다. 이것은 좋은 답변입니다
NappingRabbit

44

ReplaceAt (int 인덱스, int 길이, 문자열 바꾸기)

다음은 StringBuilder 또는 Substring을 사용하지 않는 확장 메서드입니다. 이 방법을 사용하면 대체 문자열이 소스 문자열의 길이를 넘어 확장 될 수도 있습니다.

//// 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
Stringbuilder는 문자열이 200 자보다 길면 더 효율적입니다.
Tim Schmelter 2016 년

스트레스없는. 똑바로 일했습니다. 감사합니다
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의 하위 문자열 답변)을 사용하여 세 가지 방법을 만들었습니다. SubString이 가장 빠른 방법이었습니다.
Francine DeGrood Taylor

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

6

성능에 관심이 있다면 여기서 피하고 싶은 것은 할당입니다. .Net Core 2.1+ (또는 아직 출시되지 않은 .Net Standard 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));
        });
}

이 방법은 다른 방법보다 이해하기 어렵지만 호출 당 하나의 개체 인 새로 생성 된 문자열 만 할당하는 유일한 방법입니다.


5
        string s = "ABCDEFG";
        string t = "st";
        s = s.Remove(4, t.Length);
        s = s.Insert(4, t);

이것은 작동합니다. 아마도 t다시 되돌리고 싶지 않을 것입니다 .
Pierre

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 틱과 875를 얻었습니다. 따라서 약간 느립니다.


@ Aaron.S-아니요. 내 예에서 "ABCDEFGHIJ""ZX"서로 다른 길이의이다.
John Alexiou

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

다른 모든 답변은 문자열에 유니 코드 문자 (예 : 이모티콘)가 포함되어있는 경우 작동하지 않습니다 . 유니 코드 문자가 문자보다 더 많은 바이트가되기 때문입니다.

: 이모 지 '🎶'를 바이트로 변환하면 2 자에 해당하는 가중치가 적용됩니다. 따라서 유니 코드 문자가 문자열의 시작 부분에 있으면 offset매개 변수가 이동됩니다.)

이 주제를 사용 하여 Nick Miller의 알고리즘을 유지하여 StringInfo 클래스를 Replace by position으로 확장하여 다음을 방지합니다.

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 유니 코드에서 다른 메서드가 실패하도록 할 수 없습니다. 사용 사례를 보여주기 위해 바이올린을 변경하십시오. 결과에 매우 관심이 있습니다.
Markus

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)

해결 방법 2

내 요구 사항을 충족하는 다른 솔루션은 Substring연결과 함께 사용하는 것 입니다.

string newString = oldStr.Substring(0, i) + c + oldString.Substring(i+1, oldString.Length);

이것도 괜찮습니다. 나는 생각 이 현명 첫 번째 성과로 (으로 인한 불필요한 문자열 연결에) 효율적 아니다. 그러나 조기 최적화는 모든 악의 근원입니다 .

그래서 가장 좋아하는 것을 선택하십시오 :)


솔루션 2는 작동하지만 수정이 필요합니다. string newString = oldStr.Substring (0, i) + c + oldString.Substring (i + 1, oldString.Length- (i + 1));
Yura G

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

내 해결책을 설명하겠습니다.
두 개의 문자 'Z'와 'X'를 사용하여 두 개의 특정 위치 ( "위치 4에서 위치 5로")의 문자열을 변경하는 문제 설명이 주어지면 문자열을 변경하는 데 위치 인덱스를 사용하고 문자열을 변경하는 것이 좋습니다. Replace ( ) 메서드 (실제 문자열의 일부 문자가 반복 될 가능성이 있기 때문일 수 있음), 사용 Substring()및 문자열 Concat()또는 문자열 Remove()Insert()접근 보다 목표를 달성하기 위해 미니멀 한 접근 방식을 사용하는 것을 선호합니다 . 이러한 모든 솔루션이 동일한 목표를 달성하는 목적을 달성 할 수있을 것이지만 이는 개인의 선택과 미니멀 한 접근 방식으로 정착하는 철학에 달려 있습니다.
우리가 더 자세히 살펴 봐야하는 경우, 위의 내 솔루션의 언급에 다시오고 stringStringBuilder, 둘 다 내부적으로 주어진 문자열을 문자 배열로 취급합니다. 구현을 살펴보면StringBuilderinternal 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; }

마지막으로이 솔루션은 몇 개의 문자 만 알려진 위치 색인으로 교체하는이 특정 문제에 가장 적합합니다. 요구 사항이 상당히 긴 문자열을 변경해야하는 경우, 즉 변경할 문자 수가 많은 경우 가장 적합하지 않을 수 있습니다.


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

가장 간단한 방법은 다음과 같습니다. (stringbuilder없이)

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

이것은 문자열 유형의 변수가 char 변수의 배열로 처리 될 수 있기 때문에 작동합니다. 예를 들어 이름이 "myString"인 문자열 변수의 두 번째 문자를 myString [1]로 참조 할 수 있습니다.


1
이것은 저자의 예 string에서 대체 할 문자가 각각 한 번만 발생 하기 때문에 작동합니다 . 예를 들어 이것을 실행 하면 원하는 결과가 "DBCDEFGHIE"아닌를 얻습니다 "ZBCZXFGHIX". 또한 이것이 StringBuilder2 년 반 전에 게시 된 다른 비 솔루션 보다 간단하다는 데 동의하지 않습니다 .
BACON 2013-08-31
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.