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 ())।
अदनान भट्टी

1
मुझे यह देखना था, string.Empty तुलना के लिए एक स्ट्रिंग नहीं बनाता है इसलिए यह "" की तुलना में अधिक कुशल है। ( stackoverflow.com/questions/151472/… )
टॉम सेरूल

6
क्या मैं अकेला ऐसा व्यक्ति हूँ जिसे "तर्क 2: 'स्ट्रिंग' से 'char' में परिवर्तित नहीं कर सकता" om string.Empty?
OddDev

2
@OddDev आपको यह त्रुटि तभी मिलनी चाहिए जब आपका सरणी जिसे आप लूप करते हैं वह वर्णों की सूची है। यदि वे तार हैं तो यह काम करना चाहिए
न्यूटेक डेवलपर

3
इसके अलावा, कृपया ध्यान दें कि "str.Replace" फ़ंक्शन को ठीक से काम करने के लिए, पहला पैरामीटर "स्ट्रिंग" होना चाहिए यदि आप स्ट्रिंग का उपयोग करना चाहते हैं। दूसरे पैरामीटर के रूप में खाली करें। यदि आप पहले पैरामीटर के रूप में एक चार (यानी। 'ए') का उपयोग करते हैं, तो आपको दूसरे के रूप में भी चार की आवश्यकता होगी। अन्यथा, आपको "तर्क 2: 'स्ट्रिंग' से 'चार' में परिवर्तित नहीं किया जा सकता है। त्रुटि @OddDev द्वारा उल्लिखित है
सिंह


64

RegEx के लिए एक आदर्श अनुप्रयोग की तरह लगता है - एक इंजन जो तेज पाठ हेरफेर के लिए डिज़ाइन किया गया है। इस मामले में:

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

3
ऐसा लगता है कि एक इटैलर आधारित दृष्टिकोण की तुलना में कहीं अधिक कुशल होगा, खासकर यदि आप एक संकलित Regex का उपयोग कर सकते हैं;
Ade मिलर

यह स्वीकृत उत्तर होना चाहिए, खासकर, क्योंकि @AdeMiller ने कहा, यह कहीं अधिक कुशल होगा।
ओब्सीडियन

14
यह लूप से तेज नहीं है, यह एक आम गलतफहमी है कि रेगेक्स हमेशा लूप से तेज होते हैं। रेगेक्स का जादू नहीं है, उनके मूल में उन्हें अपने संचालन को करने के लिए स्ट्रिंग के माध्यम से कुछ बिंदु पुनरावृति पर होना चाहिए, और वे रेगेक्स से ही ओवरहेड्स के साथ बहुत धीमा हो सकते हैं। वे वास्तव में बहुत जटिल हेरफेर की बात करते हैं, जहां कोड की दर्जनों लाइनें और कई छोरों की आवश्यकता होगी। 50000 बार एक सरल अडॉप्ट किए गए लूप के खिलाफ इस रेगेक्स के संकलित संस्करण का परीक्षण, रेग्ज 6X धीमा है।
टोनी चीथम

स्मृति दक्षता के बारे में क्या? नए तार आबंटन के अर्थ में नियमित अभिव्यक्ति अधिक कुशल नहीं होगी?
मारेक

2
शायद मुझे याद है जब मैंने कहा कि RegEx तेज है। जब तक यह एक बहुत तंग पाश के केंद्र में थे, तब अन्य विचार, इस तरह के एक छोटे से ऑपरेशन के लिए इस तरह की पठनीयता और रखरखाव पर प्रदर्शन पर हावी होने की संभावना है।
जॉन मेलविले

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)

(ध्यान दें: Perfऔर मेरे द्वारा लिखे गए समय के विस्तारVs हैं )

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!
मारेक



6

एक और सरल उपाय:

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


4

एक स्ट्रिंग सिर्फ एक कैरेक्टर एरे है, ताकि लिन्क को रिप्लेस करने के लिए इस्तेमाल करें (अल्बिन के समान ऊपर एक लिन्क का उपयोग करने के अलावा स्टेटमेंट में रिप्लेस करने के लिए होता है):

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

पहला स्ट्रिंग चार्ट को बदलने के लिए स्ट्रिंग है और दूसरा एक साधारण स्ट्रिंग है जिसमें चार्ट होते हैं


एल्बिन का लिनक समाधान शायद बेहतर है, जब तक कि अतिरिक्त वर्ण नहीं हैं जो आप फ़िल्टर करना चाहते हैं (व्हाट्सएप और पत्र और अंक द्वारा कवर नहीं किया गया है)।
एलिस्टेयर

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('@', ',', '.', ';', '\'');

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

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 की तरह दिखाई देगा [@,\.;']+(मिलान एक या अधिक ( +) की लगातार घटनाओं @, ,, ., ;या 'वर्ण) जहां डॉट भाग निकले होने की जरूरत नहीं है, लेकिन Regex.Escapeजरूरी होगा अन्य वर्ण कि भाग निकले किया जाना चाहिए, जैसे से बचने के लिए \, ^, ]या -जिसका स्थिति चरित्र वर्ग के अंदर आप भविष्यवाणी नहीं कर सकते।



3

यहां मैंने एक विधि लिखी है जो थोड़ा अलग दृष्टिकोण लेती है। पात्रों को हटाने के लिए निर्दिष्ट करने के बजाय, मैं अपनी विधि बताता हूं कि मैं किन पात्रों को रखना चाहता हूं - यह अन्य सभी पात्रों को हटा देगा।

ओपी के उदाहरण में, वह केवल वर्णमाला वर्ण और स्थान रखना चाहता है। यहां बताया गया है कि मेरे तरीके का कॉल कैसा लगेगा ( C # डेमो ):

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

बहुत अच्छा! संख्या में स्ट्रिंग में दो बार 0 होता है।
जॉन कुर्तज़

@ जॉन कोहर्ट्ज़ अच्छा कैच - अब गया।
मास डॉट नेट

2

यहाँ बहुत सारे अच्छे उत्तर दिए गए हैं, यहाँ कई यूनिट परीक्षणों के साथ-साथ मेरा परीक्षण भी किया जा सकता है जो परीक्षण शुद्धता की सहायता के लिए उपयोग किए जा सकते हैं, मेरा समाधान @ रियान के उपरोक्त के समान है लेकिन प्रतिस्थापन वर्णों पर O (1) लुकअप समय प्रदान करने के लिए एक ISet का उपयोग करता है (और @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

मैं इसे विस्तार विधि बनाता हूं और स्ट्रिंग सरणी के साथ, मुझे लगता 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.