C # dizesinden karakterleri kaldırma


150

Bir dizeden karakterleri nasıl kaldırabilirim? Örneğin: "My name @is ,Wan.;'; Wan".

'@', ',', '.', ';', '\''Bu dizeden karakterleri kaldırmak istiyorum böylece olur"My name is Wan Wan"

Yanıtlar:


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

Ancak, harf olmayan tüm karakterleri kaldırmak istiyorsanız başka bir yaklaşım önerebilirim

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
Bunun gibi de yapılabilir, str = new string (str.Where (x => char.IsWhiteSpace (x) || char.IsLetterOrDigit (x)). ToArray ());
Adnan Bhatti

1
Bu kadar bakmak zorunda kaldım, string.Empty karşılaştırmak için bir dize oluşturmaz böylece "" daha verimli. ( stackoverflow.com/questions/151472/… )
Tom Cerul

6
"Argüman 2: 'string' den 'char'" om string'e dönüştürülemeyen tek kişi ben miyim?
OddDev

2
@OddDev bu hatayı ancak üzerinden geçtiğiniz dizi karakter listesinden oluşuyorsa almalısınız. Eğer dizeler ise, bu işe
yaramalıdır

3
Ayrıca, ikinci parametre olarak string.Empty kullanmak istiyorsanız, "str.Replace" işlevinin düzgün çalışması için ilk parametrenin "dize" olması gerektiğini lütfen unutmayın. İlk parametre olarak bir char (yani 'a') kullanırsanız, ikinci parametre olarak bir char'a da ihtiyacınız olacaktır. Aksi takdirde, yukarıda @OddDev tarafından belirtilen "Argüman 2:" dize "den" char "a dönüştürülemez hatası alırsınız
Leo

68

Basit:

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

64

Hızlı metin kullanımı için tasarlanmış bir motor olan RegEx için ideal bir uygulama gibi geliyor. Bu durumda:

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

3
Bu, özellikle derlenmiş bir Regex kullanabiliyorsanız, yineleyici tabanlı bir yaklaşımdan çok daha verimli olacaktır;
Ade Miller

Bu kabul edilen cevap olmalıdır, çünkü @AdeMiller'in dediği gibi, çok daha verimli olacaktır.
Obsidyen

14
Bu döngüden daha hızlı değildir, normal ifadelerin döngülerden her zaman daha hızlı olduğu yaygın bir yanlış anlamadır. Regex büyülü değildir, özlerinde operasyonlarını gerçekleştirmek için bir noktada ip üzerinden tekrar etmelidirler ve normal ifadenin kendisinden genel giderlerle çok daha yavaş olabilirler. Düzinelerce kod satırı ve çoklu döngüye ihtiyaç duyulacağı son derece karmaşık manipülasyon söz konusu olduğunda gerçekten mükemmeller. Bu normal ifadenin derlenmiş sürümünü 50000 kez basit bir optimize edilmemiş döngüye karşı test ederken normal ifade 6 kat daha yavaştır.
Tony Cheetham

Bellek verimliliği ne olacak? Düzenli ifadeler yeni dizeler tahsisleri açısından daha verimli olmayacak mı?
Marek

2
RegEx'in hızlı olduğunu iddia ettiğimde belki de yanlış yazıyorum. Bu çok sıkı bir döngünün merkezinde olmadıkça, diğer hususlar, böyle bir okunabilirlik ve sürdürülebilirliğin, böyle küçük bir operasyon için performans üzerinde baskın olması muhtemeldir.
John Melville

21

Sorunuza daha az spesifik olan, normal bir ifadedeki kabul edilebilir karakterleri listeleyerek TÜM noktalama işaretlerini (boşluk hariç) bir dizeden kaldırmak mümkündür:

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 ]", "");

Cümlenizden boşluk kalmaması için bu boşluktan sonra 9 boşluk olduğunu unutmayın. Üçüncü argüman, normal ifadeye ait olmayan herhangi bir alt dizenin yerini alan boş bir dizedir.


19

Çeşitli önerilerin karşılaştırılması (hedefin çeşitli boyutları ve konumlarıyla tek karakterli değiştirmeler bağlamında karşılaştırılması).

Bu özel durumda, hedefler üzerinde bölme ve değiştirmelerde birleştirme (bu durumda, boş dize) en az 3 faktörle en hızlısıdır. kaynak ve kaynağın boyutu. #ymmv

Sonuçlar

(tam sonuç burada )

| 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] |

Test Donanımı (LinqPad)

(not: Perfve Vsolduğu zamanlama uzantıları yazdım )

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
Sonunda bazı sayılar! İyi iş @ drzaus!
Marek



6

Başka bir basit çözüm:

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

Bir dize sadece bir karakter dizisidir, bu nedenle değiştirme yapmak için Linq kullanın (değiştirmeyi yapmak için bir linq include deyimi kullanmak dışında yukarıdaki Albin'e benzer):

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

İlk dize, karakterlerin yerini alacak dize ve ikincisi karakterleri içeren basit bir dizedir


Filtrelemek istediğiniz ek karakterler (boşluk ve harf ve rakam ile kapsanmamışsa) Albin Linq çözümü muhtemelen daha iyidir.
alistair

3

Bunu buraya da atabilirim.

Dizeden karakterleri kaldırmak için bir uzantı oluşturun:

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

Ve şu şekilde kullanılabilir:

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

Veya aynen şöyle:

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

Bu, en az sayıda bellek ayırması yaptığı için en iyi çözümdür. Ayrıca, en az bellek ayırma sahip olması için yeni stringBuilder (input.Length) gibi dize oluşturucu ilk kapasitesi olarak orijinal dize uzunluğunu ayarlar.
treaschf

3

Görünüşe göre en kısa yol LINQ'yu birleştirmek ve 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 # demosuna bakın . Bunun string.Concatbir kısayol olduğunu unutmayın string.Join("", ...).

Regex'in daha yavaş olduğuna inanılmakla birlikte, bilinen tek tek karakterleri kaldırmak için bir regex kullanmanın dinamik olarak oluşturulmasının hala mümkün olduğunu unutmayın. Ancak, böyle dinamik bir regex oluşturmanın bir yolu (ihtiyacınız olan tek şey bir karakter sınıfıdır):

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

Başka bir C # demosuna bakın . Regex gibi görünecektir [@,\.;']+(eşleştirme bir veya birden fazla ( +) ardışık olaylar @, ,, ., ;veya 'karakter) nokta çıkış yapılmasını zorunlu değildir, ancak Regex.Escapediğer şekilde çıkmalıdır karakter gibi kaçmak gerekli olacaktır \, ^, ]veya -kimin pozisyon karakter sınıfının içinde tahmin edemezsiniz.



3

İşte biraz farklı bir yaklaşım gerektiren bir yöntem yazdım. Kaldırılacak karakterleri belirtmek yerine, yöntemime hangi karakterleri saklamak istediğimi söylüyorum - diğer tüm karakterleri kaldıracaktır.

OP örneğinde, sadece alfabetik karakterleri ve boşlukları tutmak istiyor. İşte benim yöntem çağrısı ( C # demo ) şöyle görünecektir :

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

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

İşte benim yöntem:

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

Müthiş cevap!
edtheprogrammerguy

Çok hoş! sayısal dizgide 0 iki kez bulunur.
John Kurtz

@JohnKurtz Güzel av - şimdi gitti.
Mass Dot Net

2

Burada çok sayıda iyi yanıt var, işte benim doğruluğumun test edilmesine yardımcı olmak için kullanılabilecek birkaç birim testi ile birlikte, benim çözümüm @ Rianne'nin yukarıdaki ile benzer, ancak değiştirme karakterlerinde O (1) arama süresi sağlamak için bir ISet kullanıyor (ve ayrıca @Albin Sunnanbo's Linq çözümü gibi).

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

Burada NUnit (2.6+) testleri

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

Genellikle aynı durumda kullandığım güçlü bir yöntem:

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

Zevk almak...


1

Eski Okul yerinde kopya / stomp:

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

Diğer yöntemler (yani C # yürütmesinde bir yan etkisi olarak gerçekleşen tüm işlev çağrıları ve örneklerin ek yükü) hakkında emin değilim.


1

Ben bu uzantı yöntemi yapmak ve dize dizisi ile, char da dize olabilir çünkü string[]daha yararlı olduğunu düşünüyorum 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;
    }
}

o zaman her yerde kullanabilirsiniz:

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

1

Bir XML dosyasından özel karakterleri kaldırmam gerekiyordu. İşte böyle yaptım. char.ToString () bu koddaki kahramandır.

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

Performans rakamlarını @ drzaus'tan alarak, en hızlı algoritmayı kullanan bir uzantı yöntemi.

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

kullanım

var name = "edward woodward!";
var removeDs = name.RemoveCharacters('d', '!');
Assert.Equal("ewar woowar", removeDs); // old joke
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.