C # 문자열에서 여러 문자 바꾸기


178

문자열을 바꾸는 더 좋은 방법이 있습니까?

Replace가 문자 배열이나 문자열 배열을 사용하지 않는다는 것에 놀랐습니다. 나는 내 자신의 확장을 작성할 수 있다고 생각하지만 다음을 수행하는 더 나은 방법이 있는지 궁금합니다. 마지막 바꾸기는 문자가 아닌 문자열입니다.

myString.Replace(';', '\n').Replace(',', '\n').Replace('\r', '\n').Replace('\t', '\n').Replace(' ', '\n').Replace("\n\n", "\n");

답변:


206

정규식 바꾸기를 사용할 수 있습니다.

s/[;,\t\r ]|[\n]{2}/\n/g
  • s/ 처음에는 검색을 의미합니다
  • [와 사이의 문자] (임의의 순서로) 검색 할 문자입니다
  • 두 번째 /는 검색 텍스트와 대체 텍스트를 구분합니다

영어로 다음과 같이 읽습니다.

" ;또는 ,또는 \t또는 \r또는 (공백) 또는 정확히 두 개의 순차 \n를 검색하여 \n"

C #에서 다음을 수행 할 수 있습니다. (가져 오기 후 System.Text.RegularExpressions)

Regex pattern = new Regex("[;,\t\r ]|[\n]{2}");
pattern.Replace(myString, "\n");

2
\t\r에 포함되어 있습니다 \s. 따라서 정규 표현식은과 같습니다 [;,\s].
NullUserException

3
그리고 \s실제로는 동등 [ \f\n\r\t\v]하므로 원래 질문에 없었던 것들을 포함시킵니다. 또한 원래 질문은 Replace("\n\n", "\n")정규식이 처리하지 않는 질문 입니다.
NullUserException

11
"c # regex performance replace"를 검색 할 때 찾은 첫 번째 벤치 마크 기사에 따르면 사용자가 구성 할 수없는 간단한 바꾸기 작업의 경우 정규 표현식을 사용하는 것이 일반 문자열 작업에 비해 매우 느리므로 최적이 아니라는 점을 고려하십시오. 시간이 느립니다.
너무

아 정규식, 힘의 상형 문자! 여기서 볼 수있는 유일한 문제는 정규식의 인간 가독성입니다. 많은 사람들이 그들을 이해하기를 거부합니다. 최근에 덜 복잡한 대안을 찾는 사람들을 위해 아래에 솔루션을 추가했습니다.
sɐunıɔ ןɐ qɐp

여러 문자를 여러 문자로 바꾸려면 어떻게 작성합니까?
Habip Oğuz

114

당신이 특히 영리하다고 느끼고 정규식을 사용하고 싶지 않은 경우 :

char[] separators = new char[]{' ',';',',','\r','\t','\n'};

string s = "this;is,\ra\t\n\n\ntest";
string[] temp = s.Split(separators, StringSplitOptions.RemoveEmptyEntries);
s = String.Join("\n", temp);

약간의 노력으로 확장 방법으로 이것을 감쌀 수 있습니다.

편집 : 또는 2 분 정도 기다리면 어쨌든 작성하게됩니다. :)

public static class ExtensionMethods
{
   public static string Replace(this string s, char[] separators, string newVal)
   {
       string[] temp;

       temp = s.Split(separators, StringSplitOptions.RemoveEmptyEntries);
       return String.Join( newVal, temp );
   }
}

그리고 짜잔 ...

char[] separators = new char[]{' ',';',',','\r','\t','\n'};
string s = "this;is,\ra\t\n\n\ntest";

s = s.Replace(separators, "\n");

특히 큰 문자열의 경우 메모리 비효율적입니다.
MarcinJuraszek

@MarcinJuraszek Lol ... 아마도 내장 문자열 메소드가 정규 표현식보다 메모리 효율성이 떨어진다는 주장을 처음 들었을 것입니다.
Paul Walls

10
네가 옳아. 게시하기 전에 측정해야했습니다. 벤치 마크를 실행하고 Regex.Replace여러 string.Replace통화 보다 8 배 이상 느립니다 . Split+ 보다 4 배 느립니다 Join. 참조 gist.github.com/MarcinJuraszek/c1437d925548561ba210a1c6ed144452
MarcinJuraszek

1
좋은 해결책! 작은 애드온. 불행히도 첫 번째 문자도 바꾸려면 작동하지 않습니다. 예제 문자열에서 't'문자를 바꾸고 싶다고 가정 해보십시오. Split 메소드는 EmptyEntry이므로 첫 번째 단어 'this'의 't'를 삭제합니다. RemoveEmptyEntries 대신 StringSplitOptions.None을 사용하는 경우 Split는 항목을 그대로두고 Join 메서드는 대신 구분 기호 문자를 추가합니다. 희망이 도움이
피에르

58

Linq의 집계 기능을 사용할 수 있습니다.

string s = "the\nquick\tbrown\rdog,jumped;over the lazy fox.";
char[] chars = new char[] { ' ', ';', ',', '\r', '\t', '\n' };
string snew = chars.Aggregate(s, (c1, c2) => c1.Replace(c2, '\n'));

확장 방법은 다음과 같습니다.

public static string ReplaceAll(this string seed, char[] chars, char replacementCharacter)
{
    return chars.Aggregate(seed, (str, cItem) => str.Replace(cItem, replacementCharacter));
}

확장 방법 사용 예 :

string snew = s.ReplaceAll(chars, '\n');

21

가장 짧은 방법입니다.

myString = Regex.Replace(myString, @"[;,\t\r ]|[\n]{2}", "\n");

1
이 하나의 라이너는 초기화 프로그램에서 필요할 때 도움이됩니다.
Guney Ozsan

8

오, 공연 공포! 대답은 약간 구식이지만 여전히 ...

public static class StringUtils
{
    #region Private members

    [ThreadStatic]
    private static StringBuilder m_ReplaceSB;

    private static StringBuilder GetReplaceSB(int capacity)
    {
        var result = m_ReplaceSB;

        if (null == result)
        {
            result = new StringBuilder(capacity);
            m_ReplaceSB = result;
        }
        else
        {
            result.Clear();
            result.EnsureCapacity(capacity);
        }

        return result;
    }


    public static string ReplaceAny(this string s, char replaceWith, params char[] chars)
    {
        if (null == chars)
            return s;

        if (null == s)
            return null;

        StringBuilder sb = null;

        for (int i = 0, count = s.Length; i < count; i++)
        {
            var temp = s[i];
            var replace = false;

            for (int j = 0, cc = chars.Length; j < cc; j++)
                if (temp == chars[j])
                {
                    if (null == sb)
                    {
                        sb = GetReplaceSB(count);
                        if (i > 0)
                            sb.Append(s, 0, i);
                    }

                    replace = true;
                    break;
                }

            if (replace)
                sb.Append(replaceWith);
            else
                if (null != sb)
                    sb.Append(temp);
        }

        return null == sb ? s : sb.ToString();
    }
}

7

문자열은 불변의 char 배열입니다.

변경 가능하게 만들어야합니다.

  • 사용하여 StringBuilder
  • unsafe세상에 가서 포인터로 놀아 라 (위험하지만)

가장 적은 횟수의 문자 배열을 반복하십시오. HashSet루프 내에서 문자 시퀀스를 순회하지 않기 때문에 여기에 유의 하십시오. 더 빠른 조회가 필요한 경우 (을 기준으로 ) HashSet최적화 된 조회로 교체 할 수 있습니다 .chararray[256]

StringBuilder를 사용한 예제

public static void MultiReplace(this StringBuilder builder, 
    char[] toReplace, 
    char replacement)
{
    HashSet<char> set = new HashSet<char>(toReplace);
    for (int i = 0; i < builder.Length; ++i)
    {
        var currentCharacter = builder[i];
        if (set.Contains(currentCharacter))
        {
            builder[i] = replacement;
        }
    }
}

편집-최적화 된 버전

public static void MultiReplace(this StringBuilder builder, 
    char[] toReplace,
    char replacement)
{
    var set = new bool[256];
    foreach (var charToReplace in toReplace)
    {
        set[charToReplace] = true;
    }
    for (int i = 0; i < builder.Length; ++i)
    {
        var currentCharacter = builder[i];
        if (set[currentCharacter])
        {
            builder[i] = replacement;
        }
    }
}

그런 다음 다음과 같이 사용하십시오.

var builder = new StringBuilder("my bad,url&slugs");
builder.MultiReplace(new []{' ', '&', ','}, '-');
var result = builder.ToString();

문자열이 wchar_t.net에 있다는 것을 기억하십시오 . 가능한 모든 문자의 부분 집합 만 바꾸는 것입니다 (그리고이를 최적화하려면 65536 부울이 필요합니다 ...)
gog

3

문자열 확장 메소드 를 작성 하여 솔루션의 어딘가에 넣을 수도 있습니다.

using System.Text;

public static class StringExtensions
{
    public static string ReplaceAll(this string original, string toBeReplaced, string newValue)
    {
        if (string.IsNullOrEmpty(original) || string.IsNullOrEmpty(toBeReplaced)) return original;
        if (newValue == null) newValue = string.Empty;
        StringBuilder sb = new StringBuilder();
        foreach (char ch in original)
        {
            if (toBeReplaced.IndexOf(ch) < 0) sb.Append(ch);
            else sb.Append(newValue);
        }
        return sb.ToString();
    }

    public static string ReplaceAll(this string original, string[] toBeReplaced, string newValue)
    {
        if (string.IsNullOrEmpty(original) || toBeReplaced == null || toBeReplaced.Length <= 0) return original;
        if (newValue == null) newValue = string.Empty;
        foreach (string str in toBeReplaced)
            if (!string.IsNullOrEmpty(str))
                original = original.Replace(str, newValue);
        return original;
    }
}


다음과 같이 호출하십시오.

"ABCDE".ReplaceAll("ACE", "xy");

xyBxyDxy


이:

"ABCDEF".ReplaceAll(new string[] { "AB", "DE", "EF" }, "xy");

xyCxyF


2

RegEx.Replace를 다음과 같이 사용하십시오.

  string input = "This is   text with   far  too   much   " + 
                 "whitespace.";
  string pattern = "[;,]";
  string replacement = "\n";
  Regex rgx = new Regex(pattern);
  string result = rgx.Replace(input, replacement);

RegEx.Replace 에 대한이 MSDN 설명서에 대한 자세한 정보는 다음과 같습니다.


1

성능-와이즈 이것은 아마도 최상의 솔루션은 아니지만 작동합니다.

var str = "filename:with&bad$separators.txt";
char[] charArray = new char[] { '#', '%', '&', '{', '}', '\\', '<', '>', '*', '?', '/', ' ', '$', '!', '\'', '"', ':', '@' };
foreach (var singleChar in charArray)
{
   str = str.Replace(singleChar, '_');
}

1
string ToBeReplaceCharacters = @"~()@#$%&amp;+,'&quot;&lt;&gt;|;\/*?";
string fileName = "filename;with<bad:separators?";

foreach (var RepChar in ToBeReplaceCharacters)
{
    fileName = fileName.Replace(RepChar.ToString(), "");
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.