c# - স্ট্রিং থেকে বিশেষ অক্ষর অপসারণ করার সবচেয়ে কার্যকর উপায়



string (16)

আচ্ছা, যদি না আপনাকে আপনার কার্যকারিতা থেকে কার্য সম্পাদন করতে না হয় তবে কেবল বজায় রাখা এবং বোঝার জন্য সবচেয়ে সহজ উপায়টি ব্যবহার করুন। একটি নিয়মিত অভিব্যক্তি এই মত দেখতে হবে:

অতিরিক্ত পারফরম্যান্সের জন্য, আপনি এটি প্রাক-কম্পাইল করতে পারেন বা শুধুমাত্র প্রথম কলটিতে কম্পাইল করতে বলুন (পরবর্তী কল দ্রুততর হবে।)

public static string RemoveSpecialCharacters(string str)
{
    return Regex.Replace(str, "[^a-zA-Z0-9_.]+", "", RegexOptions.Compiled);
}

আমি একটি স্ট্রিং থেকে সব বিশেষ অক্ষর মুছে ফেলতে চান। অনুমোদিত অক্ষরগুলি AZ (বড় হাতের অক্ষর বা ছোট হাতের অক্ষর), সংখ্যা (0-9), আন্ডারস্কোর (_), বা বিন্দু চিহ্ন (।)।

আমি নিম্নলিখিত আছে, এটা কাজ করে কিন্তু আমি সন্দেহ (আমি জানি!) এটা খুব দক্ষ নয়:

    public static string RemoveSpecialCharacters(string str)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.Length; i++)
        {
            if ((str[i] >= '0' && str[i] <= '9')
                || (str[i] >= 'A' && str[i] <= 'z'
                    || (str[i] == '.' || str[i] == '_')))
                {
                    sb.Append(str[i]);
                }
        }

        return sb.ToString();
    }

এই কাজ করার সবচেয়ে কার্যকর উপায় কি? একটি নিয়মিত অভিব্যক্তি কি মত চেহারা হবে, এবং কিভাবে এটি স্বাভাবিক স্ট্রিং ম্যানিপুলেশন সঙ্গে তুলনা করে?

পরিষ্কার করা হবে যে স্ট্রিং বরং ছোট, সাধারণত 10 এবং 30 অক্ষর মধ্যে দৈর্ঘ্য হবে।


আপনি অক্ষরগুলির একটি গতিশীল তালিকা ব্যবহার করছেন, LINQ আরও দ্রুত এবং আকর্ষক সমাধান সরবরাহ করতে পারে:

public static string RemoveSpecialCharacters(string value, char[] specialCharacters)
{
    return new String(value.Except(specialCharacters).ToArray());
}

আমি আগের দুটি "দ্রুত" পন্থা (মুক্তির সংকলন) এর বিরুদ্ধে এই পদ্ধতির তুলনা করেছি:

  • চারু অ্যারে সমাধান LukeH দ্বারা - 427 মি
  • স্ট্রিংবিল্ডার সমাধান - 429 মি
  • LINQ (এই উত্তর) - 98 মি

আলগোরিদিমটি সামান্য সংশোধন করা হয়েছে - অক্ষর হার্ড-কোডেডের পরিবর্তে একটি অ্যারে হিসাবে পাস করা হয়, যা সামান্য জিনিসগুলি প্রভাবিত করতে পারে (অর্থাত / অন্য সমাধানগুলিতে চরিত্র অ্যারে পরীক্ষা করার জন্য অভ্যন্তরীণ foor লুপ থাকবে)।

যদি আমি একটি LINQ ব্যবহার করে একটি হার্ড-কোডেড সমাধানতে স্যুইচ করি, যেখানে ফলাফলগুলি হয়, ফলাফলগুলি হল:

  • চর অ্যারে সমাধান - 7 মি
  • স্ট্রিংবিল্ডার সমাধান - 22 মি
  • LINQ - 60 মি

যদি আপনি অক্ষর তালিকা হার্ড-কোডিংয়ের পরিবর্তে আরো জেনারিক সমাধান লেখার পরিকল্পনা করছেন তবে LINQ বা একটি পরিবর্তিত পদ্ধতির দিকে তাকান। LINQ স্পষ্টভাবে আপনি সংক্ষিপ্ত, অত্যন্ত পঠনযোগ্য কোড দেয় - এমনকি Regex তুলনায় আরো।


আপনি যদি গতি সম্পর্কে চিন্তিত হন, বিদ্যমান স্ট্রিং সম্পাদনা করতে পয়েন্টার ব্যবহার করুন। আপনি স্ট্রিংটি পিন করতে এবং এতে একটি পয়েন্টার পেতে পারেন, তারপরে প্রতিটি চরিত্রের জন্য একটি লুপ চালান, প্রতিস্থাপক অক্ষর সহ প্রতিটি অবৈধ চরিত্রকে ওভাররাইট করে। এটি অত্যন্ত দক্ষ এবং কোন নতুন স্ট্রিং মেমরি বরাদ্দ করা প্রয়োজন হবে না। আপনি অনিরাপদ বিকল্প সহ আপনার মডিউলটি সংকলন করতে এবং পয়েন্টারগুলি ব্যবহার করার জন্য আপনার পদ্ধতি শিরোনামটিতে "অনিরাপদ" সংশোধনকারী যুক্ত করতে হবে।

static void Main(string[] args)
{
    string str = "string!$%with^&*invalid!!characters";
    Console.WriteLine( str ); //print original string
    FixMyString( str, ' ' );
    Console.WriteLine( str ); //print string again to verify that it has been modified
    Console.ReadLine(); //pause to leave command prompt open
}


public static unsafe void FixMyString( string str, char replacement_char )
{
    fixed (char* p_str = str)
    {
        char* c = p_str; //temp pointer, since p_str is read-only
        for (int i = 0; i < str.Length; i++, c++) //loop through each character in string, advancing the character pointer as well
            if (!IsValidChar(*c)) //check whether the current character is invalid
                (*c) = replacement_char; //overwrite character in existing string with replacement character
    }
}

public static bool IsValidChar( char c )
{
    return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '.' || c == '_');
    //return char.IsLetterOrDigit( c ) || c == '.' || c == '_'; //this may work as well
}

আমাকে কাজের জন্য একই রকম কিছু করতে হয়েছিল, কিন্তু আমার ক্ষেত্রে আমাকে এমন সব ফিল্টার ফিল্টার করতে হয়েছিল যা একটি চিঠি, নম্বর বা হোয়াইট স্পেস নয় (তবে আপনি সহজে আপনার প্রয়োজনগুলিতে এটি সংশোধন করতে পারবেন)। ফিল্টারিংটি জাভাস্ক্রিপ্টে ক্লায়েন্ট-পার্শ্ব সম্পন্ন করা হয়, তবে নিরাপত্তার কারণে আমি ফিল্টারিং সার্ভার-পার্শ্বটিও করছি। যেহেতু আমি বেশিরভাগ স্ট্রিংগুলি পরিষ্কার করতে চাই, তাই আমি স্ট্রিং অনুলিপি করতে চাই না যতক্ষন না আমি সত্যিই প্রয়োজন। এই আমার বাস্তবায়ন নিচে যাক, যা পরিষ্কার এবং নোংরা স্ট্রিং উভয় জন্য ভাল সঞ্চালন করা উচিত।

public static string EnsureOnlyLetterDigitOrWhiteSpace(string input)
{
    StringBuilder cleanedInput = null;
    for (var i = 0; i < input.Length; ++i)
    {
        var currentChar = input[i];
        var charIsValid = char.IsLetterOrDigit(currentChar) || char.IsWhiteSpace(currentChar);

        if (charIsValid)
        {
            if(cleanedInput != null)
                cleanedInput.Append(currentChar);
        }
        else
        {
            if (cleanedInput != null) continue;
            cleanedInput = new StringBuilder();
            if (i > 0)
                cleanedInput.Append(input.Substring(0, i));
        }
    }

    return cleanedInput == null ? input : cleanedInput.ToString();
}

আমি এই কোড নমুনা সঙ্গে একমত। আমি এটি স্ট্রিং টাইপ এক্সটেনশন পদ্ধতিতে এটি একমাত্র ভিন্ন। যাতে আপনি এটি একটি খুব সহজ লাইন বা কোড ব্যবহার করতে পারেন:

string test = "[email protected]#$123";
test.RemoveSpecialCharacters();

আপনার পরীক্ষার জন্য গুফাকে ধন্যবাদ।

public static class MethodExtensionHelper
    {
    public static string RemoveSpecialCharacters(this string str)
        {
            StringBuilder sb = new StringBuilder();
            foreach (char c in str)
            {
                if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
                {
                    sb.Append(c);
                }
            }
            return sb.ToString();
        }
}

আমি একটি সহজ অনুসন্ধান টেবিল তৈরি করার পরামর্শ দিচ্ছি, যা আপনি অক্ষরগুলির যেকোন সংমিশ্রণ বৈধ করার জন্য স্ট্যাটিক কন্সট্রকটারে শুরু করতে পারেন। এটি আপনাকে দ্রুত, একক চেক করতে দেয়।

সম্পাদন করা

এছাড়াও, গতির জন্য, আপনি আপনার স্ট্রিংব্লিলারের ক্ষমতাটি আপনার ইনপুট স্ট্রিংয়ের দৈর্ঘ্যে শুরু করতে চান। এই reallocations এড়াতে হবে। একসঙ্গে এই দুটি পদ্ধতি আপনাকে গতি এবং নমনীয়তা উভয় দিতে হবে।

অন্য সম্পাদনা

আমি মনে করি কম্পাইলার এটি অপ্টিমাইজ করতে পারে, কিন্তু শৈলী পাশাপাশি দক্ষতা বিষয় হিসাবে, আমি পরিবর্তে foreach সুপারিশ।


আমি নিশ্চিত নই এটি সবচেয়ে কার্যকর উপায়, কিন্তু এটি আমার জন্য কাজ করে

 Public Function RemoverTildes(stIn As String) As String
    Dim stFormD As String = stIn.Normalize(NormalizationForm.FormD)
    Dim sb As New StringBuilder()

    For ich As Integer = 0 To stFormD.Length - 1
        Dim uc As UnicodeCategory = CharUnicodeInfo.GetUnicodeCategory(stFormD(ich))
        If uc <> UnicodeCategory.NonSpacingMark Then
            sb.Append(stFormD(ich))
        End If
    Next
    Return (sb.ToString().Normalize(NormalizationForm.FormC))
End Function

একটি নিয়মিত অভিব্যক্তি দেখতে হবে:

public string RemoveSpecialChars(string input)
{
    return Regex.Replace(input, @"[^0-9a-zA-Z\._]", string.Empty);
}

কিন্তু কর্মক্ষমতা অত্যন্ত গুরুত্বপূর্ণ হলে, আমি আপনাকে "regex পাথ" নির্বাচন করার আগে কিছু benchmarks করতে সুপারিশ করছি ...


এখানে অনেকগুলি প্রস্তাবিত সমাধান রয়েছে, কিছু অন্যদের চেয়ে আরও দক্ষ, তবে সম্ভবত খুব পঠনযোগ্য নয়। এখানে এমন একটি যা সর্বাধিক দক্ষ নাও হতে পারে তবে বেশিরভাগ ক্ষেত্রেই এটি ব্যবহারযোগ্য, এবং লিংকটি লিভারেজ করা খুবই সংক্ষিপ্ত এবং পাঠযোগ্য।

string stringToclean = "This is a test.  Do not try this at home; you might get hurt. Don't believe it?";

var validPunctuation = new HashSet<char>(". -");

var cleanedVersion = new String(stringToclean.Where(x => (x >= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || validPunctuation.Contains(x)).ToArray());

var cleanedLowercaseVersion = new String(stringToclean.ToLower().Where(x => (x >= 'a' && x <= 'z') || validPunctuation.Contains(x)).ToArray());

এটা আমার জন্য ভাল মনে হচ্ছে। StringBuilder স্ট্রিংয়ের দৈর্ঘ্যের StringBuilder শুরু করতে হবে।

StringBuilder sb = new StringBuilder(str.Length);

কেন আপনার পদ্ধতি দক্ষ না মনে করেন? এটা আসলে আপনি এটি করতে পারেন যে সবচেয়ে কার্যকর উপায় এক।

আপনি অবশ্যই চরিত্রটি স্থানীয় ভেরিয়েবলে পড়তে বা অ্যারে অ্যাক্সেসের সংখ্যা কমাতে একটি সংখ্যাসূচক ব্যবহার করতে হবে:

public static string RemoveSpecialCharacters(this string str) {
   StringBuilder sb = new StringBuilder();
   foreach (char c in str) {
      if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_') {
         sb.Append(c);
      }
   }
   return sb.ToString();
}

এই দক্ষতার মত একটি পদ্ধতি তৈরি করে এমন একটি জিনিস এটি ভালভাবে স্কেল করে। এক্সিকিউশন সময় স্ট্রিং দৈর্ঘ্যের আপেক্ষিক হবে। আপনি একটি বড় স্ট্রিং ব্যবহার করতে হবে যদি কোন কদর্য বিস্ময় আছে।

সম্পাদনা:
আমি একটি দ্রুত কর্মক্ষমতা পরীক্ষা তৈরি, একটি 24 অক্ষর স্ট্রিং সঙ্গে প্রতিটি ফাংশন একটি মিলিয়ন বার চলমান। এই ফলাফল:

মূল ফাংশন: 54.5 মি।
আমার প্রস্তাবিত পরিবর্তন: 47.1 মি।
StringBilder ক্ষমতা সেটিং সঙ্গে খনি: 43.3 মি।
নিয়মিত এক্সপ্রেশন: 294.4 মি।

সম্পাদনা 2: আমি উপরের কোডে AZ এবং AZ এর মধ্যে পার্থক্য যোগ করেছি। (আমি কর্মক্ষমতা পরীক্ষার পুনরাবৃত্তি, এবং কোন উল্লেখযোগ্য পার্থক্য আছে।)

সম্পাদনা 3:
আমি পরীক্ষা + গৃহস্থালি [] সমাধান পরীক্ষিত, এবং এটি প্রায় 13 এমএস রান।

মূল্য দিতে হবে, অবশ্যই, বিশাল অনুসন্ধান টেবিলের সূচনা এবং এটি মেমরিতে রাখা। আচ্ছা, এটা অনেক বেশি তথ্য নয়, কিন্তু এত ছোট্ট ফাংশনের জন্য এটি অনেক ...

private static bool[] _lookup;

static Program() {
   _lookup = new bool[65536];
   for (char c = '0'; c <= '9'; c++) _lookup[c] = true;
   for (char c = 'A'; c <= 'Z'; c++) _lookup[c] = true;
   for (char c = 'a'; c <= 'z'; c++) _lookup[c] = true;
   _lookup['.'] = true;
   _lookup['_'] = true;
}

public static string RemoveSpecialCharacters(string str) {
   char[] buffer = new char[str.Length];
   int index = 0;
   foreach (char c in str) {
      if (_lookup[c]) {
         buffer[index] = c;
         index++;
      }
   }
   return new string(buffer, 0, index);
}

নিম্নলিখিত কোডটি নিম্নোক্ত আউটপুট আছে (উপসংহার হল আমরা কিছু অ্যারের ক্ষুদ্র সংস্থান বরাদ্দ করার জন্য কিছু স্মৃতি সংস্থান সংরক্ষণ করতে পারি):

lookup = new bool[123];

for (var c = '0'; c <= '9'; c++)
{
    lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}

for (var c = 'A'; c <= 'Z'; c++)
{
    lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}

for (var c = 'a'; c <= 'z'; c++)
{
    lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}

48: 0  
49: 1  
50: 2  
51: 3  
52: 4  
53: 5  
54: 6  
55: 7  
56: 8  
57: 9  
65: A  
66: B  
67: C  
68: D  
69: E  
70: F  
71: G  
72: H  
73: I  
74: J  
75: K  
76: L  
77: M  
78: N  
79: O  
80: P  
81: Q  
82: R  
83: S  
84: T  
85: U  
86: V  
87: W  
88: X  
89: Y  
90: Z  
97: a  
98: b  
99: c  
100: d  
101: e  
102: f  
103: g  
104: h  
105: i  
106: j  
107: k  
108: l  
109: m  
110: n  
111: o  
112: p  
113: q  
114: r  
115: s  
116: t  
117: u  
118: v  
119: w  
120: x  
121: y  
122: z  

আপনি রাশিয়ান লোকেল সমর্থন করতে নিম্নলিখিত কোড লাইনগুলি যোগ করতে পারেন (অ্যারের আকার 1104 হবে):

for (var c = 'А'; c <= 'Я'; c++)
{
    lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}

for (var c = 'а'; c <= 'я'; c++)
{
    lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}

হ্যাসসেট O (1)
এটা বিদ্যমান তুলনা তুলনায় দ্রুত কিনা তা নিশ্চিত না

private static HashSet<char> ValidChars = new HashSet<char>() { 'a', 'b', 'c', 'A', 'B', 'C', '1', '2', '3', '_' };
public static string RemoveSpecialCharacters(string str)
{
    StringBuilder sb = new StringBuilder(str.Length / 2);
    foreach (char c in str)
    {
        if (ValidChars.Contains(c)) sb.Append(c);
    }
    return sb.ToString();
}

আমি পরীক্ষা এবং গ্রহণযোগ্য উত্তর চেয়ে দ্রুত নয়।
যদি আপনি অক্ষরের একটি কনফিগারযোগ্য সেট প্রয়োজন হিসাবে আমি এটি ছেড়ে দিতে হবে এটি একটি ভাল সমাধান হবে।


public static string RemoveSpecialCharacters(string str)
{
    char[] buffer = new char[str.Length];
    int idx = 0;

    foreach (char c in str)
    {
        if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
            || (c >= 'a' && c <= 'z') || (c == '.') || (c == '_'))
        {
            buffer[idx] = c;
            idx++;
        }
    }

    return new string(buffer, 0, idx);
}

public string RemoveSpecial(string evalstr)
{
StringBuilder finalstr = new StringBuilder();
            foreach(char c in evalstr){
            int charassci = Convert.ToInt16(c);
            if (!(charassci >= 33 && charassci <= 47))// special char ???
             finalstr.append(c);
            }
return finalstr.ToString();
}

StringBuilder sb = new StringBuilder();

for (int i = 0; i < fName.Length; i++)
{
   if (char.IsLetterOrDigit(fName[i]))
    {
       sb.Append(fName[i]);
    }
}




string