c++ - কিভাবে স্টেড:: স্ট্রিং নিম্ন ক্ষেত্রে রূপান্তর করবেন?




string c++-standard-library (15)

আমি std::string ছোট হাতের অক্ষরে রূপান্তর করতে চাই। আমি ফাংশন tolower() সম্পর্কে সচেতন, তবে অতীতে আমি এই ফাংশন নিয়ে সমস্যা ছিল এবং এটি std::string ব্যবহার করে প্রতিটি চরিত্রের উপর পুনরাবৃত্তি প্রয়োজন হিসাবে যাইহোক এটা খুব কম আদর্শ।

100% সময় কাজ করে এমন একটি বিকল্প আছে কি?


100% সময় কাজ করে এমন একটি বিকল্প আছে কি?

না

একটি নিম্নচাপ পদ্ধতি নির্বাচন করার আগে আপনাকে নিজেকে জিজ্ঞাসা করতে হবে বিভিন্ন প্রশ্ন আছে।

  1. কিভাবে স্ট্রিং এনকোড করা হয়? সমতল ASCII? হল UTF-8? বর্ধিত ASCII লিগ্যাসি এনকোডিং এর কিছু ফর্ম?
  2. যাই হোক না কেন আপনি নিম্ন ক্ষেত্রে মানে? কেস ম্যাপিং নিয়ম ভাষা মধ্যে পরিবর্তিত! আপনি ব্যবহারকারী লোকেল স্থানীয়করণ করা হয় যে কিছু চান? আপনার সফটওয়্যারটি যে সমস্ত সিস্টেমে চলছে তার উপর ক্রমাগত আচরণ করে এমন কিছু চান? আপনি শুধু ASCII অক্ষর ছোট হাতের অক্ষর এবং অন্য সব মাধ্যমে পাস করতে চান?
  3. কি লাইব্রেরি পাওয়া যায়?

একবার আপনার সেই প্রশ্নের উত্তর দেওয়ার পরে আপনি আপনার প্রয়োজনীয়তার সাথে সামঞ্জস্য করার জন্য একটি সূচনা খুঁজছেন। সর্বত্র সবার জন্য কাজ করে এমন কোনও আকারের ফিট নেই!


টুকিটাকি সংকেতলিপি

#include<bits/stdc++.h>
using namespace std;


int main ()
{
    ios::sync_with_stdio(false);

    string str="String Convert\n";

    for(int i=0; i<str.size(); i++)
    {
      str[i] = tolower(str[i]);
    }
    cout<<str<<endl;

    return 0;
}


আপনি যদি কিছু সহজ চান তবে এখানে একটি ম্যাক্রো কৌশল রয়েছে:

#define STRTOLOWER(x) std::transform (x.begin(), x.end(), x.begin(), ::tolower)
#define STRTOUPPER(x) std::transform (x.begin(), x.end(), x.begin(), ::toupper)
#define STRTOUCFIRST(x) std::transform (x.begin(), x.begin()+1, x.begin(),  ::toupper); std::transform (x.begin()+1, x.end(),   x.begin()+1,::tolower)

যাইহোক, মনে রাখবেন যে এই উত্তরটি @ আন্দ্রেডাস স্পিনলারের মন্তব্যটি এখনও একটি গুরুত্বপূর্ণ বিবেচনার বিষয়, তবে যদি আপনি এমন কিছুতে কাজ করছেন যা কেবলমাত্র ASCII অক্ষর নয়।


এই জন্য একটি বুস্ট স্ট্রিং আলগোরিদিম আছে:

#include <boost/algorithm/string.hpp>    

std::string str = "HELLO, WORLD!";
boost::algorithm::to_lower(str); // modifies str

অথবা, অ-স্থানে থাকার জন্য:

#include <boost/algorithm/string.hpp>    

const std::string str = "HELLO, WORLD!";
const std::string lower_str = boost::algorithm::to_lower_copy(str);

এটি বড় হাতের অক্ষর এবং ছোট বিপরীত রূপান্তর করতে আরেকটি সহজ সংস্করণ হতে পারে। আমি এই সোর্স কোডটি কম্পাইল করার জন্য VS2017 সম্প্রদায় সংস্করণ ব্যবহার করেছি।

#include <iostream>
#include <string>
using namespace std;

int main()
{
    std::string _input = "lowercasetouppercase";
#if 0
    // My idea is to use the ascii value to convert
    char upperA = 'A';
    char lowerA = 'a';

    cout << (int)upperA << endl; // ASCII value of 'A' -> 65
    cout << (int)lowerA << endl; // ASCII value of 'a' -> 97
    // 97-65 = 32; // Difference of ASCII value of upper and lower a
#endif // 0

    cout << "Input String = " << _input.c_str() << endl;
    for (int i = 0; i < _input.length(); ++i)
    {
        _input[i] -= 32; // To convert lower to upper
#if 0
        _input[i] += 32; // To convert upper to lower
#endif // 0
    }
    cout << "Output String = " << _input.c_str() << endl;

    return 0;
}

দ্রষ্টব্য: যদি বিশেষ অক্ষর থাকে তবে শর্ত পরীক্ষা ব্যবহার করে পরিচালনা করা দরকার।


নিম্নরূপ std namespace সম্পর্কে বিরক্ত না করে নিম্ন লোকেশনে স্ট্রিং রূপান্তর করার সহজ উপায় নিম্নরূপ

1: স্পেস ছাড়া / সঙ্গে স্ট্রিং

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    getline(cin,str);
//------------function to convert string into lowercase---------------
    transform(str.begin(), str.end(), str.begin(), ::tolower);
//--------------------------------------------------------------------
    cout<<str;
    return 0;
}

2: স্পেস ছাড়া স্ট্রিং

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    cin>>str;
//------------function to convert string into lowercase---------------
    transform(str.begin(), str.end(), str.begin(), ::tolower);
//--------------------------------------------------------------------
    cout<<str;
    return 0;
}

মাইক্রোসফ্ট প্ল্যাটফর্মগুলিতে আপনি ফাংশনের strlwr পরিবারটি ব্যবহার করতে পারেন: http://msdn.microsoft.com/en-us/library/hkxwh33z.aspx

// crt_strlwr.c
// compile with: /W3
// This program uses _strlwr and _strupr to create
// uppercase and lowercase copies of a mixed-case string.
#include <string.h>
#include <stdio.h>

int main( void )
{
   char string[100] = "The String to End All Strings!";
   char * copy1 = _strdup( string ); // make two copies
   char * copy2 = _strdup( string );

   _strlwr( copy1 ); // C4996
   _strupr( copy2 ); // C4996

   printf( "Mixed: %s\n", string );
   printf( "Lower: %s\n", copy1 );
   printf( "Upper: %s\n", copy2 );

   free( copy1 );
   free( copy2 );
}

যদি স্ট্রিংটি ASCII পরিসরের বাইরে UTF-8 অক্ষর ধারণ করে তবে তারপরে :: আলগোরিদিম :: to_lower এটিকে বুস্ট করবেন না। ভাল ব্যবহার boost :: লোকেল :: to_lower যখন UTF-8 জড়িত হয়। দেখুন http://www.boost.org/doc/libs/1_51_0/libs/locale/doc/html/conversions.html


রেফারেন্স পরিবর্তনশীল সঙ্গে লুপ জন্য ভিত্তিক পরিসীমা ব্যবহার করে অন্য পদ্ধতির

string test = "Hello World";
for(auto& c : test)
{
   c = tolower(c);
}

cout<<test<<endl;

this থেকে:

#include <algorithm>
#include <string> 

std::string data = "Abc"; 
std::transform(data.begin(), data.end(), data.begin(), ::tolower);

আপনি সত্যিই প্রতিটি চরিত্র মাধ্যমে পুনরাবৃত্তি সঙ্গে দূরে পেতে যাচ্ছে না। অক্ষর ছোট হাতের অক্ষর বা বড় হাতের অক্ষর কিনা তা জানার কোন উপায় নেই।

আপনি যদি সত্যিই tolower() ঘৃণা করেন tolower() , এখানে একটি অ-পোর্টেবল বিকল্প রয়েছে যা আমি আপনাকে ব্যবহার করার সুপারিশ করি না:

char easytolower(char in) {
  if(in <= 'Z' && in >= 'A')
    return in - ('Z' - 'z');
  return in;
}

std::transform(data.begin(), data.end(), data.begin(), easytolower);

সচেতন থাকুন ::tolower() শুধুমাত্র প্রতি-একক-বাইট-চরিত্র প্রতিস্থাপন করতে পারে, যা অনেক স্ক্রিপ্টের জন্য অসুস্থ-উপযুক্ত, বিশেষ করে যদি UTF-8 মত মাল্টি-বাইট-এনকোডিং ব্যবহার করে।


বুস্টের বিকল্প হল পোকো (pocoproject.org)।

POCO দুটি রূপ প্রদান করে:

  1. প্রথম রূপটি মূল স্ট্রিংটি পরিবর্তন না করে একটি অনুলিপি তৈরি করে।
  2. দ্বিতীয় রূপটি মূল স্ট্রিংকে পরিবর্তিত করে।
    "প্লেস" সংস্করণগুলিতে সর্বদা "InPlace" নামের মধ্যে রয়েছে।

উভয় সংস্করণ নিচে প্রদর্শিত হয়:

#include "Poco/String.h"
using namespace Poco;

std::string hello("!");

// Copies "!" into 'newString' without altering 'hello.'
std::string newString(toUpper(hello));

// Changes newString in-place to read "!"
toLowerInPlace(newString);

TL; ড

আইসিইউ লাইব্রেরি ব্যবহার করুন।

প্রথমে আপনাকে একটি প্রশ্নের উত্তর দিতে হবে: আপনার std::string এর এনকোডিং কী? এটা কি ISO-8859-1? অথবা সম্ভবত আইএসও -8859-8? অথবা উইন্ডোজ কোডপোজ 1252? আপনি উপরের যে ছোট হাতের অক্ষর রূপান্তর করতে ব্যবহার করছেন তা কি জানেন? (অথবা এটি 0x7f বেশি অক্ষরের জন্য দুর্ভাগ্যজনকভাবে ব্যর্থ হয়?)

যদি আপনি ইউটিএফ -8 (8-বিট এনকোডিংগুলির মধ্যে একমাত্র সাইন পছন্দ) ব্যবহার করেন তবে std::string সাথে কন্টেইনার হিসাবে ব্যবহার করছেন, আপনি ইতিমধ্যে নিজেরাই বিশ্বাস করছেন যে আপনি এখনও কিছুতেই নিয়ন্ত্রণ করছেন কারণ আপনি একটি মাল্টিবিট অক্ষর সংরক্ষণ করছেন মাল্টিবিট ধারণার সচেতন নয় এমন একটি ধারক মধ্যে ক্রম। এমনকি .substr() হিসাবে সহজ কিছু একটি ticking .substr() । (কারণ একটি মাল্টিবিট ক্রম বিভাজন একটি অবৈধ (উপ-) স্ট্রিং হতে পারে।)

এবং যত তাড়াতাড়ি আপনি std::toupper( 'ß' ) এর মত কোনও এনকোডিং-এ চেষ্টা করেন, আপনি গভীর ঝামেলায় পড়েন। (যেহেতু এটি কেবলমাত্র "লাইব্রেরী" স্ট্যান্ডার্ড লাইব্রেরির সাথে করা সম্ভব নয়, যা শুধুমাত্র একটি ফলাফল চরিত্র প্রদান করতে পারে, "SS" এখানে প্রয়োজন হয় না।) [1] আরেকটি উদাহরণ হবে std::tolower( 'I' ) , যা লোকেলের উপর নির্ভর করে বিভিন্ন ফলাফল জন্মাতে হবে । জার্মানিতে, 'i' সঠিক হবে; তুরস্ক, 'ı' (LATIN ছোট অক্ষর ডটলেস আমি) প্রত্যাশিত ফলাফল।

তারপর আপনার পয়েন্টারটি যে মেশিনে চলছে তার উপর ভিত্তি করে স্ট্যান্ডার্ড লাইব্রেরি নির্ভর করে কোন লোকেলগুলি সমর্থিত ... এবং এটি না থাকলে আপনি কী করবেন?

সুতরাং আপনি যা খুঁজছেন তা হল একটি স্ট্রিং ক্লাস যা এটিকে সঠিকভাবে ডিল করতে সক্ষম, এবং এটি std::string

(সি ++ 11 নোট: std::u16string এবং std::u32string ভাল , তবে এখনও নিখুঁত নয়।)

Boost সুন্দর দেখায় , যদিও API, Boost.Locale মূলত ICU কাছাকাছি একটি মোড়ক। যদি বুস্টটি ICU সমর্থনের সাথে সংকলিত হয় ... যদি এটি না হয় তবে বুস্ট। লোকেলটি সাধারণ লাইব্রেরীর জন্য স্থানীয় লোকেল সমর্থনে সীমিত।

এবং আমার বিশ্বাস, ICU সঙ্গে কম্পাইল বুস্ট পেয়ে কখনও কখনও একটি বাস্তব ব্যথা হতে পারে। (উইন্ডোজের জন্য কোনও পূর্ব-সংকলিত বাইনারি নেই, তাই আপনাকে তাদের অ্যাপ্লিকেশন দিয়ে তাদের সরবরাহ করতে হবে, এবং এটি একটি সম্পূর্ণ নতুন কীট খোলে ...)

তাই ব্যক্তিগতভাবে আমি সরাসরি ইউনিকোড সমর্থন সরাসরি ঘোড়ার মুখের থেকে এবং ICU লাইব্রেরি ব্যবহার করে সরাসরি সুপারিশ করবো:

#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>

#include <iostream>

int main()
{
    char const * someString = "Eidenges\xe4\xdf";
    icu::UnicodeString someUString( someString, "ISO-8859-1" );
    // Setting the locale explicitly here for completeness.
    // Usually you would use the user-specified system locale.
    std::cout << someUString.toLower( "de_DE" ) << "\n";
    std::cout << someUString.toUpper( "de_DE" ) << "\n";
    return 0;
}

কম্পাইল (এই উদাহরণে G ++ দিয়ে):

g++ -Wall example.cpp -licuuc -licuio

এটি দেয়:

eidengesäß
EIDENGESÄSS

[1] 2017 সালে, জার্মান অর্থশাস্ত্রের কাউন্সিল শাসন করেছিল যে "ẞ" U + 1E9E ল্যাটিন ক্যাপিটাল লিটার SHARP S, আনুষ্ঠানিকভাবে "এসএস" রূপান্তরের পাশাপাশি বিকল্প হিসাবে ব্যবহার করা যেতে পারে যেমন অস্পষ্টতা এড়াতে উদাহরণস্বরূপ পাসপোর্টে (যেখানে নামগুলি পুঁজিভুক্ত করা হয় )। আমার সুন্দর যেতে-উদাহরণ, কমিটির সিদ্ধান্ত দ্বারা অপ্রচলিত করা ...


পরীক্ষা যদি না করে উপরের কেসটি নিম্নে রূপান্তর করার উপায় থাকে এবং এটি বেশ সোজা হয়। Isupper () ফাংশন / ম্যাক্রোর clocale.h এর ব্যবহার আপনার অবস্থান সম্পর্কিত সমস্যাগুলির যত্ন নিতে হবে, তবে যদি না হয়, তবে আপনি আপনার হৃদয়ের সামগ্রীতে UtoL [] কে টিক রাখতে পারেন।

যেহেতু C এর অক্ষর সত্যিই 8-বিট ইন্টস (এই মুহূর্তে বিস্তৃত চরিত্র সেটগুলি উপেক্ষা করে) আপনি একটি 256 বাইট অ্যারে তৈরি করতে পারেন একটি বিকল্প সেট অক্ষর ধারণ করে এবং রূপান্তর ফাংশনে আপনার স্ট্রিংয়ের অক্ষরগুলি সাবস্ক্রিপ্ট হিসাবে ব্যবহার করে রূপান্তর অ্যারে।

যদিও 1-এর জন্য 1 ম্যাপিংয়ের পরিবর্তে, নিম্ন-কেসের অক্ষরগুলির জন্য উপরের কেসের অ্যারের সদস্যদের BY BY int মানগুলি দিন। আপনি islower () এবং isupper () এখানে দরকারী খুঁজে পেতে পারেন।

কোড এই মত দেখায় ...

#include <clocale>
static char UtoL[256];
// ----------------------------------------------------------------------------
void InitUtoLMap()  {
    for (int i = 0; i < sizeof(UtoL); i++)  {
        if (isupper(i)) {
            UtoL[i] = (char)(i + 32);
        }   else    {
            UtoL[i] = i;
        }
    }
}
// ----------------------------------------------------------------------------
char *LowerStr(char *szMyStr) {
    char *p = szMyStr;
    // do conversion in-place so as not to require a destination buffer
    while (*p) {        // szMyStr must be null-terminated
        *p = UtoL[*p];  
        p++;
    }
    return szMyStr;
}
// ----------------------------------------------------------------------------
int main() {
    time_t start;
    char *Lowered, Upper[128];
    InitUtoLMap();
    strcpy(Upper, "Every GOOD boy does FINE!");

    Lowered = LowerStr(Upper);
    return 0;
}

এই পদ্ধতিটি, একই সময়ে, আপনি যে কোনও অক্ষরগুলি পরিবর্তন করতে চান তা পুনরায় তৈরি করতে দেয়।

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

এখানে কেউ এবিসিডিআইসিকে ASCII রূপান্তর করতে ব্যবহৃত একই পদ্ধতির সাথে এই চিন্তাকে চিনতে পারে।


//You can really just write one on the fly whenever you need one.
#include <string>
void _lower_case(std::string& s){
for(unsigned short l = s.size();l;s[--l]|=(1<<5));
}
//Here is an example.
//http://ideone.com/mw2eDK




tolower