c++ - উনল - সি++ বই




কেস+ইনসেন্সিটিভ স্ট্রিং তুলনা সি++ (20)

সমস্ত বড় হাতের অক্ষর বা সমস্ত ছোট হাতের অক্ষর রূপান্তরিত না করে C ++ তে কেস-অসংবেদনশীল স্ট্রিং তুলনা করার সর্বোত্তম উপায় কী?

ইউনিকোড বান্ধব এবং কিভাবে তারা পোর্টেবল হয় তা নির্দেশ করুন।


Boost এই জন্য একটি সহজ অ্যালগরিদম রয়েছে:

#include <boost/algorithm/string.hpp>
// Or, for fewer header dependencies:
//#include <boost/algorithm/string/predicate.hpp>

std::string str1 = "hello, world!";
std::string str2 = "HELLO, WORLD!";

if (boost::iequals(str1, str2))
{
    // Strings are identical
}

FYI, strcmp() এবং stricmp() বাফার ওভারফ্লোের জন্য ঝুঁকিপূর্ণ, কারণ এটি একটি প্রক্রিয়া সম্পন্ন না হওয়া পর্যন্ত প্রক্রিয়া করে। _strncmp() এবং _strnicmp() ব্যবহার করা নিরাপদ।


boost :: iequals স্ট্রিং ক্ষেত্রে utf-8 সামঞ্জস্যপূর্ণ নয়। আপনি boost::locale ব্যবহার করতে পারেন।

comparator<char,collator_base::secondary> cmpr;
cout << (cmpr(str1, str2) ? "str1 < str2" : "str1 >= str2") << endl;
  • প্রাথমিক - শুধুমাত্র অক্ষরগুলির তুলনা করে অ্যাকসেন্ট এবং চরিত্রের ক্ষেত্রে উপেক্ষা করুন। উদাহরণস্বরূপ "ফাডেড" এবং "ফ্যাসেড" একই।
  • সেকেন্ডারি - চরিত্র ক্ষেত্রে উপেক্ষা কিন্তু লক্ষণ বিবেচনা। "র facade" এবং "façade" ভিন্ন তবে "ফ্যাসেড" এবং "ফাডেড" একই।
  • ত্রৈমাসিক - উভয় ক্ষেত্রে এবং উচ্চারণ বিবেচনা করুন: "ফ্যাসিড" এবং "ফ্যাকড" ভিন্ন। বিরামহীনতা উপেক্ষা করুন।
  • Quaternary - সব ক্ষেত্রে, লক্ষণ, এবং বিরাম বিবেচনা। শব্দগুলি ইউনিকোড প্রতিনিধিত্বের ক্ষেত্রে অভিন্ন হতে হবে।
  • সমান - quaternary হিসাবে, কিন্তু পাশাপাশি কোড পয়েন্ট তুলনা।

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

এই রূপান্তর জন্য সেরা পদ্ধতি তুলনা করার আগে তাই করতে হয়। যখন এটি এনকোডিং স্কিমগুলি আসে তখন এটি আপনাকে নমনীয়তার একটি ভাল চুক্তি দেয়, যা আপনার প্রকৃত তুলনা অপারেটরকে অজ্ঞাত হওয়া উচিত।

আপনি অবশ্যই নিজের স্ট্রিং ফাংশন বা বর্গের পিছনে এই রূপান্তরটি লুকিয়ে রাখতে পারেন, তবে আপনাকে তুলনা করার আগে স্ট্রিংগুলিকে রূপান্তর করতে হবে।


আপনি অবশেষে যে পদ্ধতিটি চয়ন করেন তার উপর একটি নোট, যদি এমন পদ্ধতিতে strcmp ব্যবহার অন্তর্ভুক্ত থাকে যা কিছু উত্তর প্রস্তাব করে:

strcmp সাধারণভাবে ইউনিকোড তথ্য দিয়ে কাজ করে না। সাধারণভাবে, এটি বাইট-ভিত্তিক ইউনিকোড এনকোডিংগুলির সাথেও কাজ করে না, যেমন ইউটিএফ -8, যেমন strcmp শুধুমাত্র বাইট-পার-বাইটে তুলনা করে এবং ইউটিউব কোড পয়েন্টগুলি ইউটিএফ -8 এ এনকোড করা যায় এবং 1 বাইট বেশি নিতে পারে। একমাত্র নির্দিষ্ট ইউনিকোড কেস strcmp সঠিকভাবে হ্যান্ডেল করে যখন একটি বাইট-ভিত্তিক এনকোডিংয়ের সাথে এনক্রিপ্ট করা একটি স্ট্রিং U + 00FF এর নিচে কেবল কোড পয়েন্ট থাকে - তাহলে বাইটি-প্রতি-বাইাইট তুলনাটি যথেষ্ট।


আপনি ইউনিক্স, অথবা উইন্ডোজ stricmpstricmp ব্যবহার করতে পারেন।

এ পর্যন্ত উল্লেখ করা হয়নি এমন এক জিনিস হল যে যদি আপনি এই পদ্ধতিগুলির সাথে স্টল স্ট্রিংগুলি ব্যবহার করেন তবে প্রথমে দুটি স্ট্রিংগুলির দৈর্ঘ্যের সাথে তুলনা করা উপকারী, কারণ এই তথ্যটি আপনার কাছে ইতিমধ্যে স্ট্রিং ক্লাসে উপলব্ধ। আপনি তুলনা করা দুটি স্ট্রিং প্রথম স্থানে একই দৈর্ঘ্য না হলে এই ব্যয়বহুল স্ট্রিং তুলনা করতে প্রতিরোধ করতে পারে।


আপনি যদি POSIX সিস্টেমে থাকেন তবে আপনি strcasecmp ব্যবহার করতে পারেন। এই ফাংশনটি স্ট্যান্ডার্ড সি এর অংশ নয়, যদিও এটি উইন্ডোজগুলিতে উপলব্ধ নয়। এটি 8-বিট অক্ষরের ক্ষেত্রে একটি কেস-অসংবেদক তুলনা করবে, যতক্ষণ লোকেল POSIX হয়। যদি লোকেল POSIX না হয়, ফলাফলগুলি অনির্ধারিত (তাই এটি স্থানীয়করণের তুলনা করতে পারে, অথবা এটি নাও হতে পারে)। একটি প্রশস্ত চরিত্র সমতুল্য পাওয়া যায় না।

যে ব্যর্থ, ঐতিহাসিক সি লাইব্রেরী বাস্তবায়নের একটি বড় সংখ্যা stricmp () এবং strnicmp ()। উইন্ডোজ এ ভিজুয়াল সি ++ এগুলি এটিকে আন্ডারস্কোরের মাধ্যমে পূর্বাবস্থায় ফিরিয়ে আনার মাধ্যমে এই সমস্ত নামকরণ করে কারণ এটি ANSI স্ট্যান্ডার্ডের অংশ নয়, তাই সেই সিস্টেমে তারা _ স্ট্রিকম্প বা _strnicmp নামে পরিচিত। কিছু লাইব্রেরিগুলিতে বিস্তৃত অক্ষর বা মাল্টিবিট সমতুল্য ফাংশন থাকতে পারে (সাধারণত নামকরণ করা হয় যেমন wcsicmp, mbcsicmp এবং আরও)।

সি এবং সি ++ উভয়ই আন্তর্জাতিকীকরণের বিষয়গুলির অজানা, তাই তৃতীয় পক্ষের লাইব্রেরি ব্যবহার না করেই এই সমস্যার কোনও ভাল সমাধান নেই। সি / সি ++ এর জন্য একটি শক্তিশালী লাইব্রেরির প্রয়োজন হলে আইবিএম আইসিইউ (ইউনিকোডের জন্য আন্তর্জাতিক উপাদান) দেখুন । ICU উভয় উইন্ডোজ এবং ইউনিক্স সিস্টেমের জন্য।


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

তাই আমি কি সঙ্গে আসা করেছি এই হল:

bool icasecmp(const string& l, const string& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](string::value_type l1, string::value_type r1)
                { return toupper(l1) == toupper(r1); });
}

bool icasecmp(const wstring& l, const wstring& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](wstring::value_type l1, wstring::value_type r1)
                { return towupper(l1) == towupper(r1); });
}

Whar_t জন্য গৃহস্থালি এবং অন্য জন্য এক overload সঙ্গে একটি সহজ ফাংশন। যে কোনও প্ল্যাটফর্মের জন্য ভাল কিছু হওয়া উচিত নয়।

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

এমন ক্ষেত্রে যেখানে পাঠ্যের আরো পরিশীলিত লেক্সিকোগ্রাফিক ম্যানিপুলেশন প্রয়োজন হয়, তখন আপনাকে কেবলমাত্র বুস্টের মত তৃতীয় পক্ষের লাইব্রেরি ব্যবহার করতে হবে, যা প্রত্যাশিত হবে।


উপরের সমাধানগুলি তুলনা পদ্ধতি ব্যবহার করে না এবং আবার বাস্তবায়ন করা হচ্ছে তাই এখানে আমার সমাধান এবং এটি আপনার জন্য কাজ করে বলে আশা করা হচ্ছে (এটি সূক্ষ্ম কাজ করছে)।

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
string tolow(string a)
{
    for(unsigned int i=0;i<a.length();i++)
    {
        a[i]=tolower(a[i]);
    }
    return a;
}
int main()
{
    string str1,str2;
    cin>>str1>>str2;
    int temp=tolow(str1).compare(tolow(str2));
    if(temp>0)
        cout<<1;
    else if(temp==0)
        cout<<0;
    else
        cout<<-1;
}

একটি অ-ইউনিকোড সংস্করণের জন্য আমার প্রথম চিন্তাটি এমন কিছু করতে হয়েছিল:


bool caseInsensitiveStringCompare(const string& str1, const string& str2) {
    if (str1.size() != str2.size()) {
        return false;
    }
    for (string::const_iterator c1 = str1.begin(), c2 = str2.begin(); c1 != str1.end(); ++c1, ++c2) {
        if (tolower(*c1) != tolower(*c2)) {
            return false;
        }
    }
    return true;
}

পার্টির কাছে দেরী, কিন্তু এখানে এমন একটি রূপ রয়েছে যা std::locale ব্যবহার করে এবং তাই সঠিকভাবে তুরস্ক পরিচালনা করে:

auto tolower = std::bind1st(
    std::mem_fun(
        &std::ctype<char>::tolower),
    &std::use_facet<std::ctype<char> >(
        std::locale()));

অক্ষরকে ছোট হাতের অক্ষরে রূপান্তর করতে সক্রিয় লোকেল ব্যবহার করে এমন একটি ফাংশক দেয় যা আপনি std::transform মাধ্যমে নিম্ন- std::transform স্ট্রিংগুলি তৈরি করতে ব্যবহার করতে পারেন:

std::string left = "fOo";
transform(left.begin(), left.end(), left.begin(), tolower);

এই wchar_t ভিত্তিক স্ট্রিং জন্য কাজ করে।


বুস্ট ব্যবহার না করে সিটি স্ট্রিং পয়েন্টারটি c_str() ব্যবহার করে এবং strcasecmp ব্যবহার করে সম্পন্ন করা যেতে পারে:

std::string str1 ="aBcD";
std::string str2 = "AbCd";;
if (strcasecmp(str1.c_str(), str2.c_str()) == 0)
{
    //case insensitive equal 
}

সংক্ষিপ্ত এবং সুন্দর। বর্ধিত std সি lib চেয়ে অন্য কোন নির্ভরতা ,.

strcasecmp(str1.c_str(), str2.c_str()) == 0

str1 এবং str2 সমান হলে সত্য ফেরত। strcasecmp অস্তিত্ব নেই, stricmp , strcmpi ইত্যাদি হতে পারে

উদাহরণ কোড:

#include <iostream>
#include <string>
#include <string.h> //For strcasecmp(). Also could be found in <mem.h>

using namespace std;

/// Simple wrapper
inline bool str_ignoreCase_cmp(std::string const& s1, std::string const& s2) {
    if(s1.length() != s2.length())
        return false;  // optimization since std::string holds length in variable.
    return strcasecmp(s1.c_str(), s2.c_str()) == 0;
}

/// Function object - comparator
struct StringCaseInsensetiveCompare {
    bool operator()(std::string const& s1, std::string const& s2) {
        if(s1.length() != s2.length())
            return false;  // optimization since std::string holds length in variable.
        return strcasecmp(s1.c_str(), s2.c_str()) == 0;
    }
    bool operator()(const char *s1, const char * s2){ 
        return strcasecmp(s1,s2)==0;
    }
};


/// Convert bool to string
inline char const* bool2str(bool b){ return b?"true":"false"; }

int main()
{
    cout<< bool2str(strcasecmp("asd","AsD")==0) <<endl;
    cout<< bool2str(strcasecmp(string{"aasd"}.c_str(),string{"AasD"}.c_str())==0) <<endl;
    StringCaseInsensetiveCompare cmp;
    cout<< bool2str(cmp("A","a")) <<endl;
    cout<< bool2str(cmp(string{"Aaaa"},string{"aaaA"})) <<endl;
    cout<< bool2str(str_ignoreCase_cmp(string{"Aaaa"},string{"aaaA"})) <<endl;
    return 0;
}

আউটপুট:

true
true
true
true
true

সহায়তায় সমস্যাটি আপনাকে সংযুক্ত করতে এবং সহায়তার উপর নির্ভর করে। কিছু ক্ষেত্রে সহজ নয় (যেমন Android)।

এবং char_traits ব্যবহার মানে আপনার সমস্ত তুলনা কেস সংবেদনশীল, যা সাধারণত আপনি চান না।

এই যথেষ্ট করা উচিত। এটা যুক্তিসঙ্গতভাবে দক্ষ হওয়া উচিত। যদিও ইউনিকোড বা কিছু হ্যান্ডেল না।

bool iequals(const string& a, const string& b)
{
    unsigned int sz = a.size();
    if (b.size() != sz)
        return false;
    for (unsigned int i = 0; i < sz; ++i)
        if (tolower(a[i]) != tolower(b[i]))
            return false;
    return true;
}

আপডেট: বোনাস সি ++ 14 সংস্করণ ( #include <algorithm> ):

bool iequals(const string& a, const string& b)
{
    return std::equal(a.begin(), a.end(),
                      b.begin(), b.end(),
                      [](char a, char b) {
                          return tolower(a) == tolower(b);
                      });
}

২013 সালের শুরুতে, আইবিএম কর্তৃক পরিচালিত আইসিইউ প্রকল্প, এটির একটি সুন্দর উত্তর।

site.icu-project.org

আইসিইউ একটি "সম্পূর্ণ, পোর্টেবল ইউনিকোড লাইব্রেরি যা ঘনিষ্ঠভাবে শিল্পের মানগুলি ট্র্যাক করে।" স্ট্রিং তুলনা নির্দিষ্ট সমস্যা জন্য, Collation বস্তু আপনি চান কি না।

২01২ সালের মাঝামাঝি ফায়ারফক্সে আন্তর্জাতিকীকরণের জন্য মজিলা প্রকল্প আইসিইউ গ্রহণ করেছে; আপনি বিল্ডিং সিস্টেম এবং ডেটা ফাইলের আকার সহ এখানে প্রকৌশল আলোচনা ট্র্যাক করতে পারেন, এখানে:


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

@ কয়েনকিন দ্বারা উল্লেখিত স্বাভাবিকভাবেই তুলনা করার পদ্ধতিগুলি বিদ্যমান, এবং এমনকি লোকেলের জন্যও অ্যাকাউন্ট করতে পারে - উদাহরণস্বরূপ (এবং এটি একটি সাজানো উদাহরণ, কঠোরভাবে সমান নয়) স্প্যানিশ ভাষায় (স্প্যানিশ ভাষায়), চিঠির সমন্বয় "ল" "এল" এবং "এম", তাই "lz" <"ll" <"ma"।


std::lexicographical_compare :

// lexicographical_compare example
#include <iostream>  // std::cout, std::boolalpha
#include <algorithm>  // std::lexicographical_compare
#include <cctype>  // std::tolower

// a case-insensitive comparison function:
bool mycomp (char c1, char c2) {
    return std::tolower(c1)<std::tolower(c2);
}

int main () {
    char foo[] = "Apple";
    char bar[] = "apartment";

    std::cout << std::boolalpha;

    std::cout << "Comparing foo and bar lexicographically (foo < bar):\n";

    std::cout << "Using default comparison (operator<): ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9);
    std::cout << '\n';

    std::cout << "Using mycomp as comparison object: ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9, mycomp);
    std::cout << '\n';

    return 0;
}

Demo


আপনি যদি স্ট্রিং একটি ভেক্টর আছে, উদাহরণস্বরূপ:

std::sort(std::begin(myvector), std::end(myvector), [](std::string const &a, std::string const &b)
{
    return std::lexicographical_compare(std::begin(a), std::end(a), std::begin(b), std::end(b), [](std::string::value_type a, std::string::value_type b)
    {
        return std::tolower(a) < std::tolower(b); //case-insensitive
    });
});

http://ideone.com/N6sq6X


C ++ (উইন্ডোজের জন্য পরীক্ষিত) দুটি স্ট্রিং তুলনা করার একটি সহজ উপায় _ স্ট্রিকম্প ব্যবহার করছে

// Case insensitive (could use equivalent _stricmp)  
result = _stricmp( string1, string2 );  

আপনি std :: স্ট্রিং ব্যবহার করতে চান, উদাহরণস্বরূপ:

std::string s1 = string("Hello");
if ( _stricmp(s1.c_str(), "HELLO") == 0)
   std::cout << "The string are equals.";

এখানে আরও তথ্যের জন্য: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx


bool insensitive_c_compare(char A, char B){
  static char mid_c = ('Z' + 'a') / 2 + 'Z';
  static char up2lo = 'A' - 'a'; /// the offset between upper and lowers

  if ('a' >= A and A >= 'z' or 'A' >= A and 'Z' >= A)
      if ('a' >= B and B >= 'z' or 'A' >= B and 'Z' >= B)
      /// check that the character is infact a letter
      /// (trying to turn a 3 into an E would not be pretty!)
      {
        if (A > mid_c and B > mid_c or A < mid_c and B < mid_c)
        {
          return A == B;
        }
        else
        {
          if (A > mid_c)
            A = A - 'a' + 'A'; 
          if (B > mid_c)/// convert all uppercase letters to a lowercase ones
            B = B - 'a' + 'A';
          /// this could be changed to B = B + up2lo;
          return A == B;
        }
      }
}

এই সম্ভবত আরো দক্ষ করা যেতে পারে, কিন্তু এখানে তার সমস্ত বিট বেয়ার সঙ্গে একটি ভারী সংস্করণ।

সব পোর্টেবল নয়, তবে আমার কম্পিউটারে যাই হোক না কেন ভাল কাজ করে (কোনও ধারণা নেই, আমি ছবির শব্দ নয়)





string