C # 문자열에서 문자 제거


150

문자열에서 문자를 어떻게 제거합니까? 예를 들면 다음과 같습니다 "My name @is ,Wan.;'; Wan"..

'@', ',', '.', ';', '\''해당 문자열 에서 문자가 제거되도록하고 싶습니다."My name is Wan Wan"

답변:


177
var str = "My name @is ,Wan.;'; Wan";
var charsToRemove = new string[] { "@", ",", ".", ";", "'" };
foreach (var c in charsToRemove)
{
    str = str.Replace(c, string.Empty);
}

그러나 문자가 아닌 문자를 모두 제거하려면 다른 접근법을 제안 할 수 있습니다

var str = "My name @is ,Wan.;'; Wan";
str = new string((from c in str
                  where char.IsWhiteSpace(c) || char.IsLetterOrDigit(c)
                  select c
       ).ToArray());

12
다음과 같이 수행 할 수도 있습니다. str = new string (str.Where (x => char.IsWhiteSpace (x) || char.IsLetterOrDigit (x)). ToArray ());
Adnan Bhatti

1
string.Empty는 비교할 문자열을 만들지 않으므로 ""보다 효율적입니다. ( stackoverflow.com/questions/151472/… )
Tom Cerul

6
"인수 2 : 'string'에서 'char'로 변환 할 수 없습니다"om string.Empty를 얻는 유일한 사람입니까?
OddDev

2
@OddDev 루프하는 배열이 문자 목록 인 경우에만이 오류가 발생합니다. 문자열이면 작동합니다
Newteq Developer

3
또한 "str.Replace"기능이 제대로 작동하려면 string.Empty를 두 번째 매개 변수로 사용하려면 첫 번째 매개 변수는 "string"이어야합니다. 첫 번째 매개 변수로 char (즉, 'a')을 사용하는 경우 두 번째 매개 변수로 char이 필요합니다. 그렇지 않으면 위의 @OddDev에서 언급 한 "인수 2 : 'string'에서 'char'로 변환 할 수 없습니다"오류가 발생합니다.
Leo

68

단순한:

String.Join("", "My name @is ,Wan.;'; Wan".Split('@', ',' ,'.' ,';', '\''));

64

빠른 텍스트 조작을 위해 설계된 엔진 인 RegEx에 이상적인 응용 프로그램 인 것 같습니다. 이 경우 :

Regex.Replace("He\"ll,o Wo'r.ld", "[@,\\.\";'\\\\]", string.Empty)

3
컴파일 된 Regex를 사용할 수있는 경우 특히 반복자 기반 접근 방식보다 훨씬 효율적입니다.
Ade Miller

@AdeMiller가 말했듯이 훨씬 더 효율적이기 때문에 이것은 받아 들일만한 대답이어야합니다.
흑요석

14
이것은 루프보다 빠르지 않습니다. 정규 표현식이 항상 루프보다 빠르다는 일반적인 오해입니다. 정규식은 마술이 아닙니다. 핵심에서는 어느 시점에서 문자열을 반복하여 작업을 수행해야하며 정규식 자체의 오버 헤드로 인해 속도가 훨씬 느려질 수 있습니다. 수십 줄의 코드와 여러 개의 루프가 필요한 극도로 복잡한 조작에있어 정말 뛰어납니다. 이 정규식의 컴파일 된 버전을 최적화되지 않은 간단한 루프 50000 회에 대해 테스트하면 정규식이 6 배 느려집니다.
Tony Cheetham

메모리 효율성은 어떻습니까? 새로운 문자열 할당의 의미에서 정규식이 더 효율적이지 않습니까?
Marek

2
RegEx가 빠르다고 주장했을 때 어쩌면 나는 틀렸다. 이것이 매우 엄격한 루프의 중심에 있지 않은 한, 이러한 가독성과 유지 관리 성은 이와 같은 소규모 작업의 성능보다 지배적 일 수 있습니다.
John Melville

21

질문에 덜 구체적으로, 정규식에 허용되는 문자를 흰색으로 나열하여 문자열에서 공백을 제외한 모든 문장 부호를 제거 할 수 있습니다.

string dirty = "My name @is ,Wan.;'; Wan";

// only space, capital A-Z, lowercase a-z, and digits 0-9 are allowed in the string
string clean = Regex.Replace(dirty, "[^A-Za-z0-9 ]", "");

문장에서 공백을 제거하지 않도록 9 이후에 공백이 있습니다. 세 번째 인수는 정규식에 속하지 않는 하위 문자열을 대체하는 빈 문자열입니다.


19

다양한 제안을 비교하고 (단일 문자 대체의 맥락에서 다양한 크기 및 대상 위치로 비교).

이 경우 대상을 분할하고 교체 (이 경우 빈 문자열)에 참여하는 것이 최소 3 배 이상 빠릅니다. 궁극적으로 교체 횟수에 따라 성능이 달라집니다. 소스 및 소스의 크기 #ymmv

결과

(전체 결과는 여기 )

| Test                      | Compare | Elapsed                                                            |
|---------------------------|---------|--------------------------------------------------------------------|
| SplitJoin                 | 1.00x   | 29023 ticks elapsed (2.9023 ms) [in 10K reps, 0.00029023 ms per]   |
| Replace                   | 2.77x   | 80295 ticks elapsed (8.0295 ms) [in 10K reps, 0.00080295 ms per]   |
| RegexCompiled             | 5.27x   | 152869 ticks elapsed (15.2869 ms) [in 10K reps, 0.00152869 ms per] |
| LinqSplit                 | 5.43x   | 157580 ticks elapsed (15.758 ms) [in 10K reps, 0.0015758 ms per]   |
| Regex, Uncompiled         | 5.85x   | 169667 ticks elapsed (16.9667 ms) [in 10K reps, 0.00169667 ms per] |
| Regex                     | 6.81x   | 197551 ticks elapsed (19.7551 ms) [in 10K reps, 0.00197551 ms per] |
| RegexCompiled Insensitive | 7.33x   | 212789 ticks elapsed (21.2789 ms) [in 10K reps, 0.00212789 ms per] |
| Regex Insentive           | 7.52x   | 218164 ticks elapsed (21.8164 ms) [in 10K reps, 0.00218164 ms per] |

테스트 하니스 (LinqPad)

(참고 : PerfVs있는 타이밍 확장은 내가 쓴 )

void test(string title, string sample, string target, string replacement) {
    var targets = target.ToCharArray();

    var tox = "[" + target + "]";
    var x = new Regex(tox);
    var xc = new Regex(tox, RegexOptions.Compiled);
    var xci = new Regex(tox, RegexOptions.Compiled | RegexOptions.IgnoreCase);

    // no, don't dump the results
    var p = new Perf/*<string>*/();
        p.Add(string.Join(" ", title, "Replace"), n => targets.Aggregate(sample, (res, curr) => res.Replace(new string(curr, 1), replacement)));
        p.Add(string.Join(" ", title, "SplitJoin"), n => String.Join(replacement, sample.Split(targets)));
        p.Add(string.Join(" ", title, "LinqSplit"), n => String.Concat(sample.Select(c => targets.Contains(c) ? replacement : new string(c, 1))));
        p.Add(string.Join(" ", title, "Regex"), n => Regex.Replace(sample, tox, replacement));
        p.Add(string.Join(" ", title, "Regex Insentive"), n => Regex.Replace(sample, tox, replacement, RegexOptions.IgnoreCase));
        p.Add(string.Join(" ", title, "Regex, Uncompiled"), n => x.Replace(sample, replacement));
        p.Add(string.Join(" ", title, "RegexCompiled"), n => xc.Replace(sample, replacement));
        p.Add(string.Join(" ", title, "RegexCompiled Insensitive"), n => xci.Replace(sample, replacement));

    var trunc = 40;
    var header = sample.Length > trunc ? sample.Substring(0, trunc) + "..." : sample;

    p.Vs(header);
}

void Main()
{
    // also see /programming/7411438/remove-characters-from-c-sharp-string

    "Control".Perf(n => { var s = "*"; });


    var text = "My name @is ,Wan.;'; Wan";
    var clean = new[] { '@', ',', '.', ';', '\'' };

    test("stackoverflow", text, string.Concat(clean), string.Empty);


    var target = "o";
    var f = "x";
    var replacement = "1";

    var fillers = new Dictionary<string, string> {
        { "short", new String(f[0], 10) },
        { "med", new String(f[0], 300) },
        { "long", new String(f[0], 1000) },
        { "huge", new String(f[0], 10000) }
    };

    var formats = new Dictionary<string, string> {
        { "start", "{0}{1}{1}" },
        { "middle", "{1}{0}{1}" },
        { "end", "{1}{1}{0}" }
    };

    foreach(var filler in fillers)
    foreach(var format in formats) {
        var title = string.Join("-", filler.Key, format.Key);
        var sample = string.Format(format.Value, target, filler.Value);

        test(title, sample, target, replacement);
    }
}

1
마지막으로 일부 숫자! 잘 했어 @ drzaus!
Marek



6

또 다른 간단한 해결책 :

var forbiddenChars = @"@,.;'".ToCharArray();
var dirty = "My name @is ,Wan.;'; Wan";
var clean = new string(dirty.Where(c => !forbiddenChars.Contains(c)).ToArray());

5
new List<string> { "@", ",", ".", ";", "'" }.ForEach(m => str = str.Replace(m, ""));

4

문자열은 문자 배열 일 뿐이므로 Linq를 사용하여 교체를 수행하십시오 (위의 Albin과 유사하며 linq contains 문을 사용하여 교체 수행).

var resultString = new string(
        (from ch in "My name @is ,Wan.;'; Wan"
         where ! @"@,.;\'".Contains(ch)
         select ch).ToArray());

첫 번째 문자열은 문자를 바꿀 문자열이고 두 번째 문자열은 문자를 포함하는 간단한 문자열입니다.


필터링하려는 추가 문자가없는 경우 (빈칸, 문자 및 숫자로 표시되지 않음) Albin의 Linq 솔루션이 더 좋습니다.
alistair

3

나는 이것을 여기에 버릴 수도 있습니다.

문자열에서 문자를 제거하도록 확장하십시오 :

public static string RemoveChars(this string input, params char[] chars)
{
    var sb = new StringBuilder();
    for (int i = 0; i < input.Length; i++)
    {
        if (!chars.Contains(input[i]))
            sb.Append(input[i]);
    }
    return sb.ToString();
}

그리고 다음과 같이 사용할 수 있습니다 :

string str = "My name @is ,Wan.;'; Wan";
string cleanedUpString = str.RemoveChars('@', ',', '.', ';', '\'');

아니면 그냥 이렇게 :

string str = "My name @is ,Wan.;'; Wan".RemoveChars('@', ',', '.', ';', '\'');

가장 적은 수의 메모리 할당을 수행하므로이 방법이 가장 좋습니다. 또한 메모리 할당 횟수를 최소화하기 위해 new StringBuilder (input.Length)와 같이 원래 문자열의 길이를 문자열 작성기의 초기 용량으로 설정합니다.
treaschf

3

가장 짧은 방법은 LINQ와 string.Concat다음 을 결합하는 것 같습니다 .

var input = @"My name @is ,Wan.;'; Wan";
var chrs = new[] {'@', ',', '.', ';', '\''};
var result = string.Concat(input.Where(c => !chrs.Contains(c)));
// => result = "My name is Wan Wan" 

C # 데모를 참조하십시오 . 주 string.Concat에 대한 바로 가기입니다 string.Join("", ...).

정규식을 사용하여 알려진 개별 문자를 제거하면 여전히 동적으로 빌드 할 수 있지만 정규식이 느리다고 생각됩니다. 그러나 다음과 같은 동적 정규식을 작성하는 방법이 있습니다 (문자 클래스 만 있으면됩니다).

var pattern = $"[{Regex.Escape(new string(chrs))}]+";
var result = Regex.Replace(input, pattern, string.Empty);

다른 C # 데모를 참조하십시오 . 정규식처럼 보일 것이다 [@,\.;']+(일치하는 하나 이상의 ( +)의 연속 발생 @, ,, ., ;또는 '문자) 점 이스케이프 할 필요가 없습니다 만, Regex.Escape다른 이스케이프해야합니다 문자, 같은 탈출 할 필요가있다 \, ^, ]또는 -그 위치를 캐릭터 클래스 안에서는 예측할 수 없습니다.



3

여기에 약간 다른 접근 방식을 취하는 방법이 있습니다. 제거 할 문자를 지정하지 않고 메소드에 유지하려는 문자를 지정하면 다른 모든 문자가 제거됩니다.

OP의 예에서는 알파벳 문자와 공백 만 유지하려고합니다. 내 메소드 호출은 다음과 같습니다 ( C # demo ).

var str = "My name @is ,Wan.;'; Wan";

// "My name is Wan Wan"
var result = RemoveExcept(str, alphas: true, spaces: true);

내 방법은 다음과 같습니다.

/// <summary>
/// Returns a copy of the original string containing only the set of whitelisted characters.
/// </summary>
/// <param name="value">The string that will be copied and scrubbed.</param>
/// <param name="alphas">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
/// <param name="numerics">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
/// <param name="dashes">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
/// <param name="underlines">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
/// <param name="spaces">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
/// <param name="periods">If true, all decimal characters (".") will be preserved; otherwise, they will be removed.</param>
public static string RemoveExcept(string value, bool alphas = false, bool numerics = false, bool dashes = false, bool underlines = false, bool spaces = false, bool periods = false) {
    if (string.IsNullOrWhiteSpace(value)) return value;
    if (new[] { alphas, numerics, dashes, underlines, spaces, periods }.All(x => x == false)) return value;

    var whitelistChars = new HashSet<char>(string.Concat(
        alphas ? "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" : "",
        numerics ? "0123456789" : "",
        dashes ? "-" : "",
        underlines ? "_" : "",
        periods ? "." : "",
        spaces ? " " : ""
    ).ToCharArray());

    var scrubbedValue = value.Aggregate(new StringBuilder(), (sb, @char) => {
        if (whitelistChars.Contains(@char)) sb.Append(@char);
        return sb;
    }).ToString();

    return scrubbedValue;
}

멋진 답변!
edtheprogrammerguy 2016

아주 좋은! 숫자 문자열에는 0이 두 번 있습니다.
존 커츠

@JohnKurtz Nice catch-이제 사라졌습니다.
Mass Dot Net

2

여기에 좋은 답변이 많이 있습니다. 여기에 정확성을 테스트하는 데 사용할 수있는 몇 가지 단위 테스트와 함께 추가 한 것이 있습니다. 내 솔루션은 위의 @Rianne과 비슷하지만 ISet을 사용하여 대체 문자에서 O (1) 조회 시간을 제공합니다. @Albin Sunnanbo의 Linq 솔루션과 유사합니다).

    using System;
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// Returns a string with the specified characters removed.
    /// </summary>
    /// <param name="source">The string to filter.</param>
    /// <param name="removeCharacters">The characters to remove.</param>
    /// <returns>A new <see cref="System.String"/> with the specified characters removed.</returns>
    public static string Remove(this string source, IEnumerable<char> removeCharacters)
    {
        if (source == null)
        {
            throw new  ArgumentNullException("source");
        }

        if (removeCharacters == null)
        {
            throw new ArgumentNullException("removeCharacters");
        }

        // First see if we were given a collection that supports ISet
        ISet<char> replaceChars = removeCharacters as ISet<char>;

        if (replaceChars == null)
        {
            replaceChars = new HashSet<char>(removeCharacters);
        }

        IEnumerable<char> filtered = source.Where(currentChar => !replaceChars.Contains(currentChar));

        return new string(filtered.ToArray());
    }

여기서 NUnit (2.6+) 테스트

using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;

[TestFixture]
public class StringExtensionMethodsTests
{
    [TestCaseSource(typeof(StringExtensionMethodsTests_Remove_Tests))]
    public void Remove(string targetString, IEnumerable<char> removeCharacters, string expected)
    {
        string actual = StringExtensionMethods.Remove(targetString, removeCharacters);

        Assert.That(actual, Is.EqualTo(expected));
    }

    [TestCaseSource(typeof(StringExtensionMethodsTests_Remove_ParameterValidation_Tests))]
    public void Remove_ParameterValidation(string targetString, IEnumerable<char> removeCharacters)
    {
        Assert.Throws<ArgumentNullException>(() => StringExtensionMethods.Remove(targetString, removeCharacters));
    }
}

internal class StringExtensionMethodsTests_Remove_Tests : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield return new TestCaseData("My name @is ,Wan.;'; Wan", new char[] { '@', ',', '.', ';', '\'' }, "My name is Wan Wan").SetName("StringUsingCharArray");
        yield return new TestCaseData("My name @is ,Wan.;'; Wan", new HashSet<char> { '@', ',', '.', ';', '\'' }, "My name is Wan Wan").SetName("StringUsingISetCollection");
        yield return new TestCaseData(string.Empty, new char[1], string.Empty).SetName("EmptyStringNoReplacementCharactersYieldsEmptyString");
        yield return new TestCaseData(string.Empty, new char[] { 'A', 'B', 'C' }, string.Empty).SetName("EmptyStringReplacementCharsYieldsEmptyString");
        yield return new TestCaseData("No replacement characters", new char[1], "No replacement characters").SetName("StringNoReplacementCharactersYieldsString");
        yield return new TestCaseData("No characters will be replaced", new char[] { 'Z' }, "No characters will be replaced").SetName("StringNonExistantReplacementCharactersYieldsString");
        yield return new TestCaseData("AaBbCc", new char[] { 'a', 'C' }, "ABbc").SetName("CaseSensitivityReplacements");
        yield return new TestCaseData("ABC", new char[] { 'A', 'B', 'C' }, string.Empty).SetName("AllCharactersRemoved");
        yield return new TestCaseData("AABBBBBBCC", new char[] { 'A', 'B', 'C' }, string.Empty).SetName("AllCharactersRemovedMultiple");
        yield return new TestCaseData("Test That They Didn't Attempt To Use .Except() which returns distinct characters", new char[] { '(', ')' }, "Test That They Didn't Attempt To Use .Except which returns distinct characters").SetName("ValidateTheStringIsNotJustDistinctCharacters");
    }
}

internal class StringExtensionMethodsTests_Remove_ParameterValidation_Tests : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield return new TestCaseData(null, null);
        yield return new TestCaseData("valid string", null);
        yield return new TestCaseData(null, new char[1]);
    }
}

2

일반적으로 같은 경우에 사용하는 강력한 방법입니다.

private string Normalize(string text)
{
        return string.Join("",
            from ch in text
            where char.IsLetterOrDigit(ch) || char.IsWhiteSpace(ch)
            select ch);
}

즐겨...


1

구식 학교 복사 / 스톰프 :

  private static string RemoveDirtyCharsFromString(string in_string)
     {
        int index = 0;
        int removed = 0;

        byte[] in_array = Encoding.UTF8.GetBytes(in_string);

        foreach (byte element in in_array)
        {
           if ((element == ' ') ||
               (element == '-') ||
               (element == ':'))
           {
              removed++;
           }
           else
           {
              in_array[index] = element;
              index++;
           }
        }

        Array.Resize<byte>(ref in_array, (in_array.Length - removed));
        return(System.Text.Encoding.UTF8.GetString(in_array, 0, in_array.Length));
     }

다른 방법의 효율성에 대해서는 확실하지 않습니다 (즉, C # 실행의 부작용으로 발생하는 모든 함수 호출 및 인스턴스화의 오버 헤드).


1

확장 방법과 문자열 배열을 사용하면 char도 문자열이 될 수 있기 때문에 string[]보다 유용 하다고 생각 char[]합니다.

public static class Helper
{
    public static string RemoverStrs(this string str, string[] removeStrs)
    {
        foreach (var removeStr in removeStrs)
            str = str.Replace(removeStr, "");
        return str;
    }
}

그런 다음 어디서나 사용할 수 있습니다.

string myname = "My name @is ,Wan.;'; Wan";
string result = myname.RemoveStrs(new[]{ "@", ",", ".", ";", "\\"});

1

XML 파일에서 특수 문자를 제거해야했습니다. 내가 한 방법은 다음과 같습니다. char.ToString ()은이 코드의 주인공입니다.

string item = "<item type="line" />"
char DC4 = (char)0x14;
string fixed = item.Replace(DC4.ToString(), string.Empty);

1
new[] { ',', '.', ';', '\'', '@' }
.Aggregate("My name @is ,Wan.;'; Wan", (s, c) => s.Replace(c.ToString(), string.Empty)); 

1

@drzaus의 성능 수치를 보면 가장 빠른 알고리즘을 사용하는 확장 방법이 있습니다.

public static class StringEx
{
    public static string RemoveCharacters(this string s, params char[] unwantedCharacters) 
        => s == null ? null : string.Join(string.Empty, s.Split(unwantedCharacters));
}

용법

var name = "edward woodward!";
var removeDs = name.RemoveCharacters('d', '!');
Assert.Equal("ewar woowar", removeDs); // old joke
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.