স্ট্রিন্ড :: স্প্রিন্টফের মতো স্ট্রিং ফর্ম্যাটিং


454

আমি ফর্ম্যাটে আছে std::stringসঙ্গে sprintfএবং এটি ফাইল স্ট্রীম মধ্যেই পাঠিয়ে দিন। কিভাবে আমি এটি করতে পারব?


6
দীর্ঘ গল্পের সংক্ষিপ্ত ব্যবহার boost::format(কেনেটিমের সমাধান এখানে ব্যবহার করে )। boost::formatইতিমধ্যে সি ++ স্ট্রিম অপারেটরগুলিকেও সমর্থন করে! উদাহরণ: cout << format("helloworld. a=%s, b=%s, c=%s") % 123 % 123.123 % "this is a test" << endl;boost::formatকোডের সর্বনিম্ন লাইন রয়েছে ... পিয়ার-পর্যালোচনা করা হয় এবং সি ++ স্ট্রিমগুলির সাথে দুর্দান্তভাবে সংহত করে।
ট্রেভর বয়েড স্মিথ

@ অ্যাকোনাল - সম্প্রদায়ের পক্ষে (আমি আমার প্রতিনিধি সম্পর্কে কম চিন্তা করতে পারি না) আমি আপনাকে পরামর্শ দিয়েছি যে আপনার নির্বাচনটি পরিবর্তন করুন। বর্তমানে নির্বাচিত একটি, প্রথম স্নিপেটে, একটি স্বেচ্ছাসেবী সর্বোচ্চ দৈর্ঘ্যের ব্যবহারের জন্য অপেক্ষা করার জন্য একটি বাগ উপস্থাপন করে। দ্বিতীয় স্নিপেট স্প্রিন্টফের মতো বিভিন্ন ধরণের ব্যবহারের আপনার বর্ণিত ইচ্ছাটিকে সম্পূর্ণ উপেক্ষা করে completely আমি আপনাকে এখানে কেবল উত্তরটি নির্বাচন করার পরামর্শ দিচ্ছি যা পরিষ্কার, নিরাপদ, কেবলমাত্র সি ++ স্ট্যান্ডার্ডের উপর নির্ভর করে, পরীক্ষিত এবং ভাল মন্তব্য করা হয়। এটি আমার যা প্রাসঙ্গিক নয়। এটা উদ্দেশ্যমূলকভাবে সত্য। স্ট্যাকওভারফ্লো . com/ প্রশ্ন / 2342162/ … দেখুন ।
ডগলাস ড্যাসেকো

@TrevorBoydSmith একটি std::formatসি ++ 20 BTW যোগ করা হয়েছিল: stackoverflow.com/a/57286312/895245 অসাধারণ!
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli আমি প্রায় এক নিবন্ধ পড়া C++20যে শুধু গতকাল এবং আমি দেখেছি C++20কপি boostযুক্ত করে (বর্তমানে দশলক্ষ ভাগের ভাগ সময় জন্য) std::formatকরার C++20বৈশিষ্ট! আমি খুব খুশি! আমি গত 9 বছরে লিখেছি প্রায় প্রতিটি সি ++ ফাইল ব্যবহার করেছি boost::format। সি ++ এ স্ট্রিমগুলিতে অফিশিয়াল প্রিন্টফ স্টাইল আউটপুট যুক্ত করা সমস্ত সি ++ এর জন্য অনেক দীর্ঘ আইএমও করবে।
ট্রেভর বয়েড স্মিথ

উত্তর:


332

আপনি এটি সরাসরি করতে পারবেন না, কারণ অন্তর্নিহিত বাফারটিতে আপনার লেখার অ্যাক্সেস নেই (সি ++ 11 অবধি; ডায়েরিচ এপ্পের মন্তব্য দেখুন )। আপনাকে প্রথমে এটি একটি সি-স্ট্রিংয়ে করতে হবে, তারপরে এটি একটি স্টাডি :: স্ট্রিংয়ে অনুলিপি করুন:

  char buff[100];
  snprintf(buff, sizeof(buff), "%s", "Hello");
  std::string buffAsStdStr = buff;

তবে আমি নিশ্চিত নই আপনি কেন কেবল স্ট্রিং স্ট্রিম ব্যবহার করবেন না? আমি ধরে নিচ্ছি যে কেবলমাত্র এটি না করার জন্য আপনার নির্দিষ্ট কারণ রয়েছে:

  std::ostringstream stringStream;
  stringStream << "Hello";
  std::string copyOfStr = stringStream.str();

16
ম্যাজিক কুকিটি char buf[100];এই সমাধানটিকে খুব মজবুত করে না। তবে প্রয়োজনীয় ধারণাটি আছে।
জন ডিবলিং

18
জন, স্রোত ধীর নয়। স্ট্রিমগুলি ধীর বলে মনে করার একমাত্র কারণ হ'ল ডিফল্টরূপে আইস্ট্রিমগুলি সি ফাইল আউটপুটটির সাথে সিঙ্ক্রোনাইজ হয় যাতে আন্তঃসংযোগযুক্ত কাউট এবং প্রিন্টফগুলি সঠিকভাবে আউটপুট হয়। এই লিঙ্কটি অক্ষম করা (cout.sync_with_stdio (মিথ্যা) একটি কল দিয়ে) সি ++ এর স্ট্রিমকে কমপক্ষে এমএসভিসি 10 হিসাবে স্টেডিওকে ছাড়িয়ে যায়।
জিম্বো

72
ফর্ম্যাটগুলি ব্যবহার করার কারণটি হ'ল কোনও স্থানীয়করণকারীর পক্ষে বাক্যটির ব্যাকরণকে কঠোর কোডিংয়ের পরিবর্তে বিদেশী ভাষার জন্য বাক্যটির কাঠামোটি পুনরায় তৈরি করা দেওয়া।
মার্টিজান আদালত

215
কোনও কারণে, অন্যান্য ভাষাগুলি প্রিন্টফ-এর মতো সিনট্যাক্স ব্যবহার করে: জাভা, পাইথন (নতুন সিনট্যাক্স প্রবাহের চেয়ে প্রিন্টফের আরও কাছে)। কেবল সি ++ নিরপরাধ মানুষের উপর এই শব্দটির ঘৃণা চাপায়।
কোয়ান্ট_দেব

9
আরও ভাল, ব্যবহার করুন asprintf, যা ফলাফলটি রাখার জন্য পর্যাপ্ত স্থান সহ একটি নতুন স্ট্রিং বরাদ্দ করে। তারপরে std::stringআপনার পছন্দ হলে এটি অনুলিপি করুন এবং মনে রাখবেন freeমূলটি। এছাড়াও, এটি ম্যাক্রোতে রাখা সম্ভব যাতে কোনও ভাল সংকলক আপনার জন্য ফর্ম্যাটটি বৈধতা দিতে সহায়তা করে - আপনি doubleযেখানে %sপ্রত্যাশিত এমন কোনও স্থান রাখতে চান না
অ্যারন ম্যাকডেইড

284

আধুনিক সি ++ এটিকে অতি সাধারণ করে তোলে।

সি ++ 20

সি ++ ২০ টি পরিচয় করিয়ে std::formatদেয় যা আপনাকে ঠিক এটি করতে দেয়। এটি পাইথনের মতো প্রতিস্থাপন ক্ষেত্রগুলি ব্যবহার করে :

#include <iostream>
#include <format>

int main() {
    std::cout << std::format("Hello {}!\n", "world");
}

সম্পূর্ণ ডকুমেন্টেশন পরীক্ষা করে দেখুন ! এটি জীবনের বিশাল মানের উন্নতি।


সি ++ 11

সঙ্গে সি ++ 11 এর std::snprintf, এই ইতিমধ্যে একটি বেশ সহজ এবং নিরাপদ কাজের হয়ে ওঠে।

#include <memory>
#include <string>
#include <stdexcept>

template<typename ... Args>
std::string string_format( const std::string& format, Args ... args )
{
    size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
    if( size <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
    std::unique_ptr<char[]> buf( new char[ size ] ); 
    snprintf( buf.get(), size, format.c_str(), args ... );
    return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
}

উপরের কোড স্নিপেট সিসি ০.০ এর অধীনে লাইসেন্সযুক্ত ।

লাইন দ্বারা লাইন ব্যাখ্যা:

লক্ষ্য:char* ব্যবহার করে একটি লিখুনstd::snprintfএবং তারপরে এটিকে রূপান্তর করুনstd::string

প্রথমে, আমরা একটি বিশেষ শর্তটি ব্যবহার করে চর অ্যারের পছন্দসই দৈর্ঘ্য নির্ধারণ করি snprintfসিপ্রেফারেন্স.কম থেকে :

ফেরত মূল্য

[...] যদি বুফ_সাইজ সীমাবদ্ধতার কারণে ফলাফলটি স্ট্রিংটি কেটে ফেলা হয় তবে ফাংশনটি মোট অক্ষরের সংখ্যা প্রদান করে (শূন্যকরণ নাল-বাইট সহ নয়) যা লিখিত হত, যদি সীমাটি আরোপিত না হয়।

এর অর্থ হ'ল কাঙ্ক্ষিত আকারটি হ'ল অক্ষরের সংখ্যা এবং এক , যাতে নাল-টার্মিনেটর অন্য সমস্ত অক্ষরের পরে বসবে এবং এটি আবার স্ট্রিং কনস্ট্রাক্টর দ্বারা কেটে ফেলা যায়। @ ইলেক্সক 7 মন্তব্যগুলিতে এই বিষয়টি ব্যাখ্যা করেছেন।

size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1;

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

if( size <= 0 ){ throw std::runtime_error( "Error during formatting." ); }

এর পরে, আমরা একটি নতুন অক্ষর অ্যারে বরাদ্দ করি এবং এটি এটিকে নির্ধারণ করি std::unique_ptr। এটি সাধারণত পরামর্শ দেওয়া হয়, কারণ আপনাকে deleteএটি আর ম্যানুয়ালি করতে হবে না ।

নোট করুন যে এটি unique_ptrব্যবহারকারী-সংজ্ঞায়িত প্রকারের সাথে বরাদ্দ দেওয়ার নিরাপদ উপায় নয় কারণ আপনি যদি নির্মাণকর্তা কোনও ব্যতিক্রম ছুঁড়ে ফেলেন তবে মেমরিটি হ্রাস করতে পারবেন না!

std::unique_ptr<char[]> buf( new char[ size ] );

এর পরে, আমরা অবশ্যই snprintfএটির উদ্দেশ্যে ব্যবহারের জন্য ব্যবহার করতে পারি এবং বিন্যাসিত স্ট্রিংটি লিখতে পারি char[]

snprintf( buf.get(), size, format.c_str(), args ... );

শেষ পর্যন্ত, আমরা std::stringএটিকে থেকে একটি নতুন তৈরি এবং ফিরিয়ে দিই, শেষে নাল-টার্মিনেটর বাদ দেওয়ার বিষয়টি নিশ্চিত করে।

return std::string( buf.get(), buf.get() + size - 1 );

আপনি এখানে কর্মের একটি উদাহরণ দেখতে পারেন ।


আপনি যদি std::stringতর্ক তালিকায় ব্যবহার করতে চান তবে এই টুকরোটিটি একবার দেখুন ।


ভিজ্যুয়াল স্টুডিও ব্যবহারকারীদের জন্য অতিরিক্ত তথ্য :

এই উত্তরে যেমন বর্ণনা করা হয়েছে , মাইক্রোসফ্ট (হ্যাঁ, ছাড়া ) এর নতুন নামকরণ std::snprintfকরেছে । এমএস এটিকে আরও অবহেলিত হিসাবে সেট করে এবং পরিবর্তে ব্যবহারের পরামর্শ দেয় তবে যাইহোক বাফারটিকে ফর্ম্যাট করা আউটপুটের তুলনায় শূন্য বা তার থেকে ছোট হিসাবে গ্রহণ করবে না এবং যদি ঘটে তবে আউটপুটগুলির দৈর্ঘ্য গণনা করবে না। তাই সংকলনের সময় হ্রাসকারী সতর্কতা থেকে মুক্তি পাওয়ার জন্য, আপনি ফাইলের শীর্ষে নীচের লাইনটি সন্নিবেশ করতে পারেন যার ব্যবহার রয়েছে :_snprintfstd::_snprintf_s_snprintf_s_snprintf

#pragma warning(disable : 4996)

সর্বশেষ ভাবনা

এই প্রশ্নের অনেকগুলি উত্তর সি ++ 11-এর আগে লেখা হয়েছিল এবং নির্দিষ্ট বাফার দৈর্ঘ্য বা বর্ণগুলি ব্যবহার করেছিল। আপনি সি ++ এর পুরানো সংস্করণগুলিতে আটকে না থাকলে আমি এই সমাধানগুলি ব্যবহার করার পরামর্শ দেব না। আদর্শভাবে, সি ++ 20 পথে যান।

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

স্থানটির দক্ষতা যদি অতি গুরুত্বপূর্ণ হয় তবে ভার্জ এবং ভার্সনপ্রিন্টফ সহ এই দুটি সমাধান কার্যকর হতে পারে। স্থির বাফার দৈর্ঘ্যের কোনও সমাধান ব্যবহার করবেন না , এটি কেবল সমস্যার জন্য জিজ্ঞাসা করছে।


2
দয়া করে ভিসুয়াল স্টুডিও ব্যবহারকারীদের বনাম সংস্করণ থাকতে হবে কমপক্ষে 2013 থেকে জন্য আপনার উত্তর জোর দেওয়া এই : নিবন্ধটি আপনাকে দেখতে পারেন এটি শুধুমাত্র VS2013 সংস্করণের সাথে কাজ করে তাহলে বাফার একটি নাল পয়েন্টার এবং গণনা শূন্য হয়, লেন যেমন ফিরিয়ে দেওয়া হয় আউটপুট ফর্ম্যাট করতে প্রয়োজনীয় অক্ষরগুলির গণনা, সমাপ্তি নাল সহ নয়। একই যুক্তি এবং স্থানীয় প্যারামিটারগুলির সাথে একটি সফল কল করতে, কমপক্ষে লেন + 1 টি অক্ষর ধারণ করে একটি বাফার বরাদ্দ করুন।

3
@moooeeeep একাধিক কারণ প্রথমত, এখানে লক্ষ্যটি একটি স্ট্রাইড :: স্ট্রিংটি ফিরিয়ে আনা, কোনও সি-স্ট্রিং নয়, সুতরাং আপনি সম্ভবত বোঝাতে চেয়েছিলেন return string(&buf[0], size);বা অনুরূপ কিছু। দ্বিতীয়ত, আপনি যদি এর মতো কোনও সি-স্ট্রিং ফিরিয়ে দেন তবে এটি অপরিজ্ঞাত আচরণের কারণ হতে পারে কারণ যে ভেক্টরটি আপনাকে নির্দেশিত মানগুলিকে ধারণ করে তারা ফেরতের সময় অবৈধ হয়ে যাবে। তৃতীয়ত, যখন আমি সি ++ শিখতে শুরু করি তখন স্ট্যান্ডার্ডটি কোনও অভ্যন্তরের ভিতরে কোন ক্রমের উপাদানগুলি সংরক্ষণ করতে হয় তা নির্ধারণ করে না std::vector, সুতরাং এটির পয়েন্টারের মাধ্যমে স্টোরেজ অ্যাক্সেস করা অপরিজ্ঞাত আচরণ ছিল। এখন এটি কাজ করবে তবে আমি সেভাবে এটি করে কোনও লাভ দেখছি না।
iFreilicht

2
@iFreilicht ফাংশন স্বাক্ষরের পরামর্শ অনুসারে একটি নতুন স্পষ্টত std::stringরূপান্তরিত ভেক্টর ( অনুলিপি প্রারম্ভিকরণ ) থেকে নির্মিত হবে, যা পরে অনুলিপি হিসাবে ফিরে আসে। এছাড়াও, এ এর ​​উপাদানগুলি হ'ল std::vectorএবং সর্বদা স্বচ্ছন্দভাবে সংরক্ষণ করা হবে । তবে আমি আপনার বক্তব্য গ্রহণ করি যে এটি করার ফলে কোনও লাভ হবে না।
মূইলিপ

4
আমি এই সমাধানটি সত্যিই পছন্দ করি, তবে আমি মনে করি লাইনটি অন্যথায় return string(buf.get(), buf.get() + size);হওয়া উচিত return string(buf.get(), buf.get() + size - 1);আপনি শেষে নাল চরিত্রের সাথে একটি স্ট্রিং পান। আমি এটি জিসিসি ৪.৯-তে কেস হিসাবে পেয়েছি।
ফিল উইলিয়ামস

3
একটি এসটিডি :: স্ট্রিংকে% s তে পাস করার ফলে একটি সংকলন ত্রুটি ঘটায় ( ত্রুটি: অ-তুচ্ছ টাইপের 'std :: __ cxx11 :: বেসিক_স্ট্রিং <char>' এর ভেরিয়াদিক ফাংশনের মাধ্যমে অবজেক্টটি পাস করতে পারে না; রান রানটাইমে কলটি বাতিল করা হবে [-ভন-পড -varargs] ) ঝাঁকুনিতে 3.9.1 এ, তবে সিএল 19 এ এটি সূক্ষ্ম সংকলন করে এবং পরিবর্তে রানটাইমে ক্রাশ হয়। যে কোনও সতর্কতা পতাকা আমি চালু করতে পারি যে সেটিকে ক্লিপ করার সময়ও জিজ্ঞাসা করা হয়েছিল?
জিতরেক্স

241

সি ++ 11 সমাধান যা vsnprintf()অভ্যন্তরীণভাবে ব্যবহার করে:

#include <stdarg.h>  // For va_start, etc.

std::string string_format(const std::string fmt, ...) {
    int size = ((int)fmt.size()) * 2 + 50;   // Use a rubric appropriate for your code
    std::string str;
    va_list ap;
    while (1) {     // Maximum two passes on a POSIX system...
        str.resize(size);
        va_start(ap, fmt);
        int n = vsnprintf((char *)str.data(), size, fmt.c_str(), ap);
        va_end(ap);
        if (n > -1 && n < size) {  // Everything worked
            str.resize(n);
            return str;
        }
        if (n > -1)  // Needed size returned
            size = n + 1;   // For null char
        else
            size *= 2;      // Guess at a larger size (OS specific)
    }
    return str;
}

একটি নিরাপদ এবং আরও দক্ষ (আমি এটি পরীক্ষা করেছি এবং এটি আরও দ্রুত) পদ্ধতির:

#include <stdarg.h>  // For va_start, etc.
#include <memory>    // For std::unique_ptr

std::string string_format(const std::string fmt_str, ...) {
    int final_n, n = ((int)fmt_str.size()) * 2; /* Reserve two times as much as the length of the fmt_str */
    std::unique_ptr<char[]> formatted;
    va_list ap;
    while(1) {
        formatted.reset(new char[n]); /* Wrap the plain char array into the unique_ptr */
        strcpy(&formatted[0], fmt_str.c_str());
        va_start(ap, fmt_str);
        final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
        va_end(ap);
        if (final_n < 0 || final_n >= n)
            n += abs(final_n - n + 1);
        else
            break;
    }
    return std::string(formatted.get());
}

fmt_strমান দ্বারা গৃহীত হয় প্রয়োজনের সঙ্গে সামঞ্জস্য থেকে va_start

দ্রষ্টব্য: "নিরাপদ" এবং "দ্রুত" সংস্করণ কিছু সিস্টেমে কাজ করে না। সুতরাং উভয় এখনও তালিকাভুক্ত করা হয়। এছাড়াও, "দ্রুত" পুরোপুরি পূর্বনির্ধারিত ধাপটি সঠিক হওয়ার উপর নির্ভর করে, অন্যথায় strcpyএটি ধীর করে দেয়।


3
মন্থর। কেন 1 দ্বারা আকার বৃদ্ধি? এবং এই ফানসিটন কখন -1 ফিরবে?
0xDEAD BEEF

27
আপনি ওভাররাইট করছেন str.c_str ()? তা কি বিপজ্জনক নয়?
কোয়ান্টাম

8
একটি রেফারেন্স আর্গুমেন্ট সহ va_start এমএসভিসিতে সমস্যা রয়েছে। এটি নিঃশব্দে ব্যর্থ হয় এবং এলোমেলো স্মৃতিতে পয়েন্টার দেয়। কার্যকারণ হিসাবে স্ট্যান্ড :: স্ট্রিং ও এফএমটি এর পরিবর্তে std :: স্ট্রিং এফএমটি ব্যবহার করুন, বা একটি মোড়কের বস্তু লিখুন।
স্টিভ হ্যানভ

6
আমি +1 করেছি কারণ আমি জানি যে এটি সম্ভবত সবচেয়ে স্ট্যান্ড :: স্ট্রিংগুলি কীভাবে বাস্তবায়িত হয় তার উপর ভিত্তি করে কাজ করবে, তবে সি_এসআরটি আসলে অন্তর্নিহিত স্ট্রিংটি সংশোধন করার জায়গা হওয়ার উদ্দেশ্যে নয়। এটি কেবল পঠনযোগ্য বলে মনে করা হচ্ছে।
ডগ টি।

6
এবং ফলাফলের স্ট্রিংয়ের দৈর্ঘ্য আগেই পেতে, দেখুন: stackoverflow.com/a/7825892/908336 আমি sizeপ্রতিটি পুনরাবৃত্তির ক্রমবর্ধমান বিন্দুটি দেখতে পাচ্ছি না , যখন আপনি এটি প্রথম কলটি দ্বারা গ্রহণ করতে পারবেন vsnprintf()
মাসউদ খারী

107

boost::format() আপনি চান কার্যকারিতা সরবরাহ করে:

বুস্ট ফর্ম্যাট লাইব্রেরি সংক্ষেপ থেকে:

একটি ফর্ম্যাট অবজেক্ট ফর্ম্যাট-স্ট্রিং থেকে তৈরি করা হয়, এবং তারপরে অপারেটর% কে বার বার কল করার মাধ্যমে আর্গুমেন্ট দেওয়া হয়। এই আর্গুমেন্টগুলির প্রত্যেকটি তারপরে স্ট্রিংয়ে রূপান্তরিত হয়, যারা ফর্ম্যাট-স্ট্রিং অনুসারে পরিবর্তিত হয়ে একটি স্ট্রিংয়ে একত্রিত হয়।

#include <boost/format.hpp>

cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
// prints "writing toto,  x=40.230 : 50-th try"

5
আপনার যে লাইব্রেরিগুলি দরকার সেগুলি ছাঁটাই করতে পারেন। সরবরাহিত সরঞ্জাম ব্যবহার করা।
হাসান সৈয়দ

7
বুস্ট ফর্ম্যাটটি কেবল বড় নয়, তবে খুব ধীর। দেখুন zverovich.net/2013/09/07/... এবং boost.org/doc/libs/1_52_0/libs/spirit/doc/html/spirit/karma/...
vitaut

13
আপনার প্রকল্পের যে কোনও জায়গায় বুস্ট সহ তাত্ক্ষণিকভাবে উল্লেখযোগ্যভাবে বার সংকলন বৃদ্ধি পায়। বড় প্রকল্পগুলির জন্য, এটি সম্ভবত সবচেয়ে গুরুত্বপূর্ণ নয়। ছোট প্রকল্পের জন্য, বুস্ট একটি টানা হয়।
কোয়ান্ট_দেব

2
@vitaut এটা হয় ভয়ঙ্কর গ্রাসকারী যখন বিকল্প তুলনায় সম্পদ। আপনি কতক্ষণ স্ট্রিংগুলি ফর্ম্যাট করেন? এটি বিবেচনা করে কেবল কয়েক মাইক্রো সেকেন্ড সময় লাগে এবং বেশিরভাগ প্রকল্পগুলি সম্ভবত কয়েক ডজন বার এটি ব্যবহার করে, এমন কোনও প্রকল্পে এটি লক্ষণীয় নয় যা স্ট্রিং ফর্ম্যাটিংয়ে খুব বেশি মনোযোগ দেয় না, তাই না?
আতুরস্যামস

2
দুর্ভাগ্যক্রমে, বুস্ট :: ফর্ম্যাটটি একইভাবে কাজ করে না: var_args গ্রহণ করে না। কিছু লোক একক প্রোগ্রাম সম্পর্কিত সমস্ত কোড একই দেখতে দেখতে / একই আইডিয়মগুলি ব্যবহার করতে পছন্দ করে।
xor007

88

সি ++ ২০ এর মধ্যে অন্তর্ভুক্ত থাকবে std::formatযা sprintfএপিআই এর সাথে সাদৃশ্যযুক্ত তবে সম্পূর্ণ টাইপ-নিরাপদ, ব্যবহারকারী-সংজ্ঞায়িত প্রকারের সাথে কাজ করে এবং পাইথন-এর মতো বিন্যাসের স্ট্রিং সিনট্যাক্স ব্যবহার করে। আপনি এখানে std::stringকোনও স্ট্রিমে ফর্ম্যাট এবং লিখতে সক্ষম হবেন তা এখানে :

std::string s = "foo";
std::cout << std::format("Look, a string: {}", s);

অথবা

std::string s = "foo";
puts(std::format("Look, a string: {}", s).c_str());

বিকল্পভাবে, আপনি স্ট্রিংকে ফর্ম্যাট করতে এবং এটিতে বা একটি ফাইল স্ট্রিম একবারে লিখতে {fmt} লাইব্রেরি ব্যবহার stdoutকরতে পারেন:

fmt::print(f, "Look, a string: {}", s); // where f is a file stream

এখানে sprintfবা অন্যান্য উত্তরগুলির বেশিরভাগ হিসাবে , দুর্ভাগ্যক্রমে তারা ভারার্গস ব্যবহার করে এবং আপনি জিসিসির formatবৈশিষ্ট্যের মতো এমন কিছু ব্যবহার না করেন যা কেবল আক্ষরিক বিন্যাসের স্ট্রিংয়ের সাথে কাজ করে unless নীচের উদাহরণে এই ফাংশনগুলি অনিরাপদ কেন আপনি দেখতে পারেন:

std::string format_str = "%s";
string_format(format_str, format_str[0]);

string_formatএরিক আরোনস্টির উত্তর থেকে বাস্তবায়ন কোথায় ? এই কোডটি সংকলন করে, তবে আপনি যখন এটি চালানোর চেষ্টা করবেন তখন সম্ভবত এটি ক্রাশ হবে:

$ g++ -Wall -Wextra -pedantic test.cc 
$ ./a.out 
Segmentation fault: 11

দাবি অস্বীকার: আমি {fmt} এবং C ++ 20 এর লেখক std::format


আইএমএইচও আপনি এতে অন্তর্ভুক্তিকে মিস করেন error: 'fmt' has not been declared
সর্জিও

এটি কেবল একটি স্নিপেট, সম্পূর্ণ কোড নয়। স্পষ্টতই আপনাকে <fmt / format.h> অন্তর্ভুক্ত করতে হবে এবং কোডটি একটি ফাংশনে রাখতে হবে।
ভিটাউট

আমার পক্ষে এতটা সুস্পষ্ট নয়, আইএমএইচও আপনার এটি স্নিপেটে অন্তর্ভুক্ত করা উচিত, প্রতিক্রিয়ার জন্য ধন্যবাদ
সেরজিও

1
এর fmtমতো একটি বাস্তবায়ন সি ++ ২০ এ যুক্ত হয়েছিল! stackoverflow.com/a/57286312/895245 বর্তমানে FMT দাবি এটি জন্য সমর্থন। অসাধারণ কাজ!
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

2
@ ভিটাউট আপনার এই কাজের জন্য ধন্যবাদ!
কর্ট নিকোলস

18

আপনি যদি কেবল একটি প্রিন্টফ-এর মতো সিনট্যাক্স চান (নিজেকে প্রিন্টফকে কল না করে), বুস্ট ফর্ম্যাটটি দেখুন


এত সাধারণ জিনিসের জন্য একটি সম্পূর্ণ লাইব্রেরি যুক্ত করা নেসেকারি নয়। এটি স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / ১৯০০০৯৯৪/২ তে উত্তর দেওয়া হয়েছিল ।
ডগলাস ড্যাসেকো

15

আমি ভার্সনপ্রিন্টফ ব্যবহার করে আমার নিজস্ব লিখেছি যাতে এটি আমার নিজের বাফার তৈরি না করে স্ট্রিংটি ফিরে আসে।

#include <string>
#include <cstdarg>

//missing string printf
//this is safe and convenient but not exactly efficient
inline std::string format(const char* fmt, ...){
    int size = 512;
    char* buffer = 0;
    buffer = new char[size];
    va_list vl;
    va_start(vl, fmt);
    int nsize = vsnprintf(buffer, size, fmt, vl);
    if(size<=nsize){ //fail delete buffer and try again
        delete[] buffer;
        buffer = 0;
        buffer = new char[nsize+1]; //+1 for /0
        nsize = vsnprintf(buffer, size, fmt, vl);
    }
    std::string ret(buffer);
    va_end(vl);
    delete[] buffer;
    return ret;
}

সুতরাং আপনি এটি ব্যবহার করতে পারেন

std::string mystr = format("%s %d %10.5f", "omg", 1, 10.5);

এটি ডেটার একটি সম্পূর্ণ অতিরিক্ত অনুলিপি করে, vsnprintfসরাসরি স্ট্রিংয়ে ব্যবহার করা সম্ভব ।
মাকিং হাঁস

1
ফলাফল আগেই স্ট্রিং দৈর্ঘ্য পেতে স্ট্যাকওভারফ্লো . com/a/7825892/908336 এ কোডটি ব্যবহার করুন । এবং আপনি একটি ব্যতিক্রম-নিরাপদ কোডের জন্য স্মার্ট পয়েন্টার ব্যবহার করতে পারেন:std::unique_ptr<char[]> buffer (new char[size]);
মাসউদ খারী

আমি নিশ্চিত না যে ফলব্যাকের ক্ষেত্রে এটি সঠিক কিনা; আমি মনে করি আপনার যুক্তি সঠিকভাবে দেখতে দ্বিতীয় vsnprintf () এর জন্য vl এর একটি va_copy করা দরকার। উদাহরণস্বরূপ দেখুন: github.com/haberman/upb/blob/…
জোশ হাবম্যান

15

std::stringএকটি 'স্প্রিন্টফ' পদ্ধতিতে ফর্ম্যাট করার জন্য , প্রয়োজনীয় বাফারের দৈর্ঘ্য পেতে কল করুন snprintf(যুক্তি nullptrএবং 0)। এই জাতীয় সি ++ 11 ভেরিয়েডিক টেম্পলেট ব্যবহার করে আপনার ফাংশনটি লিখুন:

#include <cstdio>
#include <string>
#include <cassert>

template< typename... Args >
std::string string_sprintf( const char* format, Args... args ) {
  int length = std::snprintf( nullptr, 0, format, args... );
  assert( length >= 0 );

  char* buf = new char[length + 1];
  std::snprintf( buf, length + 1, format, args... );

  std::string str( buf );
  delete[] buf;
  return str;
}

সি ++ 11 সমর্থন সহ সংকলন করুন, উদাহরণস্বরূপ জিসিসিতে: g++ -std=c++11

ব্যবহার:

  std::cout << string_sprintf("%g, %g\n", 1.23, 0.001);

এসটিডি :: স্নিপ্রিন্টফ উপাচার্য ++ 12 (ভিজ্যুয়াল স্টুডিও 2013) এ উপলভ্য নয়। পরিবর্তে _স্নিপ্রিন্টফ দিয়ে এটি প্রতিস্থাপন করুন।
শীতল শাহ

আপনি char buf[length + 1];পরিবর্তে ব্যবহার করবেন না কেন char* buf = new char[length + 1];?
Behrouz.M

নতুন char[]এবং ব্যবহারের মধ্যে পার্থক্যটি char*হ'ল আগের ক্ষেত্রে বুফে স্ট্যাকের জন্য বরাদ্দ দেওয়া হত। এটি ছোট বাফারদের জন্য ঠিক আছে তবে আমরা যেহেতু ফলাফলের স্ট্রিংয়ের আকারের গ্যারান্টি দিতে পারি না তাই এটি ব্যবহার করা কিছুটা ভাল new। উদাহরণস্বরূপ আমার মেশিনে string_sprintf("value: %020000000d",5), 5 নম্বরের আগে নেতৃস্থানীয় জিরোগুলির মুখ্য সংখ্যা মুদ্রণ করুন, স্ট্যাকের মধ্যে অ্যারে ব্যবহার করার সময় কোর ডাম্পগুলি কার্যকর হয় তবে গতিশীলভাবে বরাদ্দ করা অ্যারে ব্যবহার করার সময় ঠিক আছেnew char[length + 1]
user2622016

ফর্ম্যাটেড আউটপুটটির জন্য প্রয়োজনীয় আসল বাফের আকারটি পেতে খুব চতুর ধারণা
ক্রিস

1
@ user2622016: সমাধানের জন্য ধন্যবাদ! দয়া করে মনে রাখবেন যে std::move এটি অতিমাত্রায় রয়েছে
মিহাই টডর

14

[সম্পাদনা: 20/05/25] আরও ভাল ...:
শিরোনামে:

// `say` prints the values
// `says` returns a string instead of printing
// `sayss` appends the values to it's first argument instead of printing
// `sayerr` prints the values and returns `false` (useful for return statement fail-report)<br/>

void PRINTSTRING(const std::string &s); //cater for GUI, terminal, whatever..
template<typename...P> void say(P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str(); PRINTSTRING(r); }
template<typename...P> std::string says(P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str(); return r; }
template<typename...P> void sayss(std::string &s, P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str();  s+=r; } //APPENDS! to s!
template<typename...P> bool sayerr(P...p) { std::string r{}; std::stringstream ss("ERROR: "); (ss<<...<<p); r=ss.str(); PRINTSTRING(r); return false; }

PRINTSTRING(r)-Function গুই বা টার্মিনাল অথবা কোনো বিশেষ আউটপুট চাহিদা ব্যবহার করার জন্য খাদ্যাদি হয় #ifdef _some_flag_, ডিফল্ট হল:

void PRINTSTRING(const std::string &s) { std::cout << s << std::flush; }

['17 / 8/31 সম্পাদনা করুন] একটি বৈকল্পিক টেম্পলেটড সংস্করণ 'vtspf (..)' যুক্ত করা হচ্ছে:

template<typename T> const std::string type_to_string(const T &v)
{
    std::ostringstream ss;
    ss << v;
    return ss.str();
};

template<typename T> const T string_to_type(const std::string &str)
{
    std::istringstream ss(str);
    T ret;
    ss >> ret;
    return ret;
};

template<typename...P> void vtspf_priv(std::string &s) {}

template<typename H, typename...P> void vtspf_priv(std::string &s, H h, P...p)
{
    s+=type_to_string(h);
    vtspf_priv(s, p...);
}

template<typename...P> std::string temp_vtspf(P...p)
{
    std::string s("");
    vtspf_priv(s, p...);
    return s;
}

যা কার্যকরভাবে কমা- <<বিস্মৃত সংস্করণ (পরিবর্তে) কখনও কখনও বাধা- রক্ষাকারীদের-এর মতো ব্যবহার করা হয়:

char chSpace=' ';
double pi=3.1415;
std::string sWorld="World", str_var;
str_var = vtspf("Hello", ',', chSpace, sWorld, ", pi=", pi);


[সম্পাদনা] এরিক অ্যারোনস্টির উত্তরের (উপরে) কৌশলটি ব্যবহার করতে অভিযোজিত:

#include <string>
#include <cstdarg>
#include <cstdio>

//=============================================================================
void spf(std::string &s, const std::string fmt, ...)
{
    int n, size=100;
    bool b=false;
    va_list marker;

    while (!b)
    {
        s.resize(size);
        va_start(marker, fmt);
        n = vsnprintf((char*)s.c_str(), size, fmt.c_str(), marker);
        va_end(marker);
        if ((n>0) && ((b=(n<size))==true)) s.resize(n); else size*=2;
    }
}

//=============================================================================
void spfa(std::string &s, const std::string fmt, ...)
{
    std::string ss;
    int n, size=100;
    bool b=false;
    va_list marker;

    while (!b)
    {
        ss.resize(size);
        va_start(marker, fmt);
        n = vsnprintf((char*)ss.c_str(), size, fmt.c_str(), marker);
        va_end(marker);
        if ((n>0) && ((b=(n<size))==true)) ss.resize(n); else size*=2;
    }
    s += ss;
}

[পূর্ববর্তী উত্তর]
খুব দেরিতে উত্তর, তবে যারা আমার মতো 'স্প্রিন্টফ' -র মতো করেন: আমি লিখেছি এবং নিম্নলিখিত ফাংশনগুলি ব্যবহার করছি। আপনি যদি এটি পছন্দ করেন তবে স্প্রিন্টফের সাথে আরও ঘনিষ্ঠভাবে ফিট করার জন্য আপনি%-অংশগুলি প্রসারিত করতে পারেন; সেখানে থাকা বর্তমানে আমার প্রয়োজনের জন্য যথেষ্ট। আপনি স্প্রিন্টফের মতো স্ট্রিংফ () এবং স্ট্রিংফ্যাপেন্ড () ব্যবহার করেন। কেবল মনে রাখবেন ... এর প্যারামিটারগুলি অবশ্যই পিওডি ধরণের হওয়া উচিত।

//=============================================================================
void DoFormatting(std::string& sF, const char* sformat, va_list marker)
{
    char *s, ch=0;
    int n, i=0, m;
    long l;
    double d;
    std::string sf = sformat;
    std::stringstream ss;

    m = sf.length();
    while (i<m)
    {
        ch = sf.at(i);
        if (ch == '%')
        {
            i++;
            if (i<m)
            {
                ch = sf.at(i);
                switch(ch)
                {
                    case 's': { s = va_arg(marker, char*);  ss << s;         } break;
                    case 'c': { n = va_arg(marker, int);    ss << (char)n;   } break;
                    case 'd': { n = va_arg(marker, int);    ss << (int)n;    } break;
                    case 'l': { l = va_arg(marker, long);   ss << (long)l;   } break;
                    case 'f': { d = va_arg(marker, double); ss << (float)d;  } break;
                    case 'e': { d = va_arg(marker, double); ss << (double)d; } break;
                    case 'X':
                    case 'x':
                        {
                            if (++i<m)
                            {
                                ss << std::hex << std::setiosflags (std::ios_base::showbase);
                                if (ch == 'X') ss << std::setiosflags (std::ios_base::uppercase);
                                char ch2 = sf.at(i);
                                if (ch2 == 'c') { n = va_arg(marker, int);  ss << std::hex << (char)n; }
                                else if (ch2 == 'd') { n = va_arg(marker, int); ss << std::hex << (int)n; }
                                else if (ch2 == 'l') { l = va_arg(marker, long);    ss << std::hex << (long)l; }
                                else ss << '%' << ch << ch2;
                                ss << std::resetiosflags (std::ios_base::showbase | std::ios_base::uppercase) << std::dec;
                            }
                        } break;
                    case '%': { ss << '%'; } break;
                    default:
                    {
                        ss << "%" << ch;
                        //i = m; //get out of loop
                    }
                }
            }
        }
        else ss << ch;
        i++;
    }
    va_end(marker);
    sF = ss.str();
}

//=============================================================================
void stringf(string& stgt,const char *sformat, ... )
{
    va_list marker;
    va_start(marker, sformat);
    DoFormatting(stgt, sformat, marker);
}

//=============================================================================
void stringfappend(string& stgt,const char *sformat, ... )
{
    string sF = "";
    va_list marker;
    va_start(marker, sformat);
    DoFormatting(sF, sformat, marker);
    stgt += sF;
}

@ মুভিংডাক: অ্যারনেস্টির উত্তরের ড্যানের মন্তব্য অনুসারে ফাংশন প্যারামিটার পরিবর্তিত হয়েছে। আমি কেবল লিনাক্স / জিসিসি ব্যবহার করি এবং fmtরেফারেন্স হিসাবে এটি দুর্দান্ত কাজ করে। (তবে আমি মনে করি লোকেরা খেলনা নিয়ে খেলতে চাইবে, তাই ...) অন্য কোনও অনুমিত 'বাগ' থাকলে আপনি কী দয়া করে বিস্তারিত বলতে পারেন?
স্ল্যাশমেজ

আমি ভুল বুঝেছিলাম যে তার কোডটির কিছু অংশ কীভাবে কাজ করেছে এবং ভেবেছিল যে এটি অনেক আকারের সাথে এটি করছে। পুনরায় পরীক্ষা করা দেখায় যে আমার ভুল হয়েছিল। আপনার কোডটি সঠিক।
মাকিং হাঁস

এরিক অ্যারনেস্টির উত্তরটি বন্ধ করা একটি লাল রঙের হেরিং। তার প্রথম কোডের নমুনাটি অনিরাপদ এবং দ্বিতীয়টি অদক্ষ ও আনাড়ি। পরিষ্কার বাস্তবায়ন স্পষ্টভাবে ইঙ্গিত করে যে, ফাংশনগুলির কোনও ভিপ্রিন্টফ পরিবারের বুফ_সিজো যদি শূন্য হয় তবে কিছুই লিখিত হয় না এবং বাফার একটি নাল পয়েন্টার হতে পারে, তবে ফেরতের মান (বাইট সংখ্যা যা অন্তর্ভুক্ত নয় এমনটি লেখা হবে) নাল টার্মিনেটর) এখনও গণনা করা হয় এবং ফিরে আসে। : একটি প্রকাশনা গুণমানের উত্তর এখানে stackoverflow.com/questions/2342162/...
ডগলাস Daseeco

10

গুগল এটি এটি করে: StringPrintf(বিএসডি লাইসেন্স)
এবং ফেসবুক এটি বেশ অনুরূপ ফ্যাশনে করে: StringPrintf(অ্যাপাচি লাইসেন্স)
উভয়ই একটি সুবিধাজনক সরবরাহ StringAppendFকরে।


10

এই খুব জনপ্রিয় প্রশ্নে আমার দুটি সেন্ট।

পছন্দসই ফাংশনের ম্যানপেজটিprintf উদ্ধৃত করতে :

সফল প্রত্যাবর্তনের পরে, এই ফাংশনগুলি মুদ্রিত অক্ষরের সংখ্যা প্রদান করে (স্ট্রিংগুলিতে আউটপুট শেষ করতে ব্যবহৃত নাল বাইট বাদে)।

স্নপ্রিন্টফ () এবং ভার্সনপ্রিন্টফ () ফাংশনগুলি আকার বাইটের চেয়ে বেশি লিখবে না (সমাপ্ত নাল বাইট ('\ 0') সহ)। যদি এই সীমাবদ্ধতার কারণে যদি আউটপুট কেটে ফেলা হয় তবে প্রত্যাবর্তনের মান হ'ল অক্ষরের সংখ্যা (সমাপ্ত নাল বাইট বাদ দিয়ে) যা পর্যাপ্ত স্থান উপলব্ধ থাকলে চূড়ান্ত স্ট্রিংয়ে লেখা হত। সুতরাং আকার বা তারও বেশি ফেরতের মান মানে আউটপুট কেটে গেছে।

অন্য কথায়, একটি বুদ্ধিমান সি ++ 11 বাস্তবায়ন নিম্নলিখিত হওয়া উচিত:

#include <string>
#include <cstdio>

template <typename... Ts>
std::string fmt (const std::string &fmt, Ts... vs)
{
    char b;
    size_t required = std::snprintf(&b, 0, fmt.c_str(), vs...) + 1;
        // See comments: the +1 is necessary, while the first parameter
        //               can also be set to nullptr

    char bytes[required];
    std::snprintf(bytes, required, fmt.c_str(), vs...);

    return std::string(bytes);
}

এটি বেশ ভাল কাজ করে :)

ভারিয়াদিক টেম্পলেটগুলি কেবল সি ++ 11 এ সমর্থিত। পিক্সেলপয়েন্ট থেকে উত্তর পুরানো প্রোগ্রামিং শৈলী ব্যবহার করে অনুরূপ কৌশল দেখায়।

এটি অদ্ভুত যে বাক্সের বাইরে সি ++ এর মতো জিনিস নেই। তারা সম্প্রতি যুক্ত করেছে to_string(), যা আমার মতে একটি দুর্দান্ত পদক্ষেপ। আমি ভাবছি তারা শেষ পর্যন্ত কোনও .formatঅপারেটর যুক্ত করবে কিনা std::string...

সম্পাদন করা

অ্যালেক্সক As হিসাবে উল্লেখ করা হয়েছে, A +1এর রিটার্ন ভ্যালুতে std::snprintfপ্রয়োজনীয়, যেহেতু আমাদের \0বাইটের জন্য জায়গা থাকা দরকার । স্বজ্ঞাতভাবে, বেশিরভাগ আর্কিটেকচারে অনুপস্থিতির +1ফলে requiredপূর্ণসংখ্যাটি একটি দ্বারা আংশিকভাবে ওভাররাইট হয়ে যায় 0। এটি প্রকৃত পরামিতি হিসাবে মূল্যায়নের পরে ঘটবে , সুতরাং প্রভাবটি দৃশ্যমান হওয়া উচিত নয়।requiredstd::snprintf

এই সমস্যাটি অবশ্য সংকলক অপ্টিমাইজেশনের সাথে পরিবর্তিত হতে পারে: যদি সংকলকটি চলকটির জন্য কোনও রেজিস্টার ব্যবহার করার সিদ্ধান্ত নেয় required? এটি এমন ধরণের ত্রুটি যার ফলে কখনও কখনও সুরক্ষার সমস্যা দেখা দেয়।


1
snprintf সর্বদা একটি নাল-বাইট সমাপ্তি সংযোজন করে তবে এগুলি ছাড়াই অক্ষরের সংখ্যা প্রদান করে। এই কোডটি সর্বদা শেষ চরিত্রটি এড়িয়ে যায় না?
alexk7

@ অ্যালেক্সক, ভালো লাগছে! আমি উত্তর আপডেট করছি। কোডটি শেষ চরিত্রটি এড়ায় না, তবে bytesবাফারের সমাপ্তি ছাড়িয়ে সম্ভবত requiredপূর্ণসংখ্যার উপর দিয়ে লিখেছেন (যা ভাগ্যক্রমে সেই সময়ে ইতিমধ্যে মূল্যায়ন করা হয়েছে)।
ডাকাভ

1
কেবলমাত্র একটি ছোট্ট ইঙ্গিত: 0 টি বাফার আকারের সাথে, আপনি আপনার কোডের লাইনটি সরিয়ে nullptrবাদ দিয়ে যুক্তি হিসাবে পাস করতে পারেন char b;। ( উত্স )
iFreilicht

@iFreilicht, ঠিক আছে। এছাড়াও +1
ডাকাভ

2
"চর বাইটস [প্রয়োজনীয়]" ব্যবহার করে স্তূপের পরিবর্তে স্ট্যাকের বরাদ্দ দেওয়া হবে, এটি বড় ফর্ম্যাট স্ট্রিংগুলিতে বিপজ্জনক হতে পারে। পরিবর্তে একটি নতুন ব্যবহার বিবেচনা করুন। ইয়ানান
ইয়ানুথ

9
template<typename... Args>
std::string string_format(const char* fmt, Args... args)
{
    size_t size = snprintf(nullptr, 0, fmt, args...);
    std::string buf;
    buf.reserve(size + 1);
    buf.resize(size);
    snprintf(&buf[0], size + 1, fmt, args...);
    return buf;
}

সি 99 স্নিপ্রিন্টফ এবং সি ++ 11 ব্যবহার করা


8

পরীক্ষিত, উত্পাদন মানের উত্তর

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

#include <string>
#include <cstdarg>
#include <vector>

// requires at least C++11
const std::string vformat(const char * const zcFormat, ...) {

    // initialize use of the variable argument array
    va_list vaArgs;
    va_start(vaArgs, zcFormat);

    // reliably acquire the size
    // from a copy of the variable argument array
    // and a functionally reliable call to mock the formatting
    va_list vaArgsCopy;
    va_copy(vaArgsCopy, vaArgs);
    const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy);
    va_end(vaArgsCopy);

    // return a formatted string without risking memory mismanagement
    // and without assuming any compiler or platform specific behavior
    std::vector<char> zc(iLen + 1);
    std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
    va_end(vaArgs);
    return std::string(zc.data(), iLen); }

#include <ctime>
#include <iostream>
#include <iomanip>

// demonstration of use
int main() {

    std::time_t t = std::time(nullptr);
    std::cerr
        << std::put_time(std::localtime(& t), "%D %T")
        << " [debug]: "
        << vformat("Int 1 is %d, Int 2 is %d, Int 3 is %d", 11, 22, 33)
        << std::endl;
    return 0; }

অনুমানযোগ্য লিনিয়ার দক্ষতা

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

ওভারফ্লোতে পুনরায় চেষ্টা করা তাত্পর্যপূর্ণভাবে অদক্ষ, যা সি ++ 11 স্ট্যান্ডার্ড কমিটি যখন লেখার বাফারটি বাতিল হয়ে যায় তখন ড্রাই ড্রাই দেওয়ার জন্য উপরের প্রস্তাবটি নিয়ে আলোচনা করার পরে অন্য কারণ হিসাবে আলোচিত হয়।

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

সুরক্ষা এবং নির্ভরযোগ্যতা

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

বিকল্প হিসাবে স্প্রিন্টফ, সি 9 এক্স রিভিশন প্রস্তাব , আইএসও আইসিসি ডকুমেন্ট ডাব্লুজি 14 এন 645 / এক্স 3 জ 11 96-008 এ নাল বাফার বৈশিষ্ট্যের জন্য আনুষ্ঠানিক মান সংশোধন প্রস্তাবনায় উল্লেখ করা হয়েছে । গতিশীল মেমরির সহজলভ্যতার সীমাবদ্ধতার মধ্যে প্রিন্ট ডাইরেক্টিভ ""% s "অনুযায়ী ইচ্ছামত দীর্ঘ স্ট্রিং anোকানো ব্যতিক্রম নয় এবং উত্পাদন করার জন্য শোষণ করা উচিত নয়," অব্যর্থ ধারণা সংক্রান্ত কার্যকারিতা। "

এই উত্তরের প্রথম অনুচ্ছেদে লিঙ্কযুক্ত সি ++ রেফারেন্স.org পৃষ্ঠার নীচে প্রদত্ত উদাহরণ কোডটির পাশের প্রস্তাবটি বিবেচনা করুন।

এছাড়াও, ব্যর্থতার ক্ষেত্রে পরীক্ষাগুলি সাফল্যের ক্ষেত্রে খুব কমই শক্তিশালী।

পোর্টেবিলিটি

সমস্ত বড় ওএস বিক্রেতারা সি ++ 11 মানের অংশ হিসাবে স্ট্যান্ড :: ভিএনপ্রিন্টফকে সম্পূর্ণ সমর্থন করে এমন সংকলক সরবরাহ করে। বিক্রেতাদের চলমান পণ্যগুলি যা বিতরণগুলি আর রক্ষণাবেক্ষণ করে না তা g ++ বা ঝাঁকুনি ++ সহ অনেক কারণে সজ্জিত করা উচিত।

স্ট্যাক ব্যবহার

স্ট্যান্ড :: ভিনপ্রিন্টফের 1 ম কলটিতে স্ট্যাকের ব্যবহার 2 য় এর চেয়ে কম বা সমান হবে এবং ২ য় কল শুরু হওয়ার আগেই এটি মুক্ত করা হবে। যদি প্রথম কলটি স্ট্যাকের প্রাপ্যতা ছাড়িয়ে যায়, তবে std :: fprintf ব্যর্থ হবে।


সংক্ষিপ্ত এবং মজবুত। এটি এইচপি-ইউএক্স, আইআরআইএক্স, ট্রু 64৪ এ ব্যর্থ হতে পারে যার ভার্সনপ্রিন্ট বনাম রয়েছে। সম্পাদনা: এছাড়াও, দ্বি-পাসগুলি পারফরম্যান্সে কীভাবে প্রভাব ফেলতে পারে তা বিবেচনা করে, esp। সর্বাধিক সাধারণ, ছোট স্ট্রিং ফর্ম্যাটিংয়ের জন্য, আপনি কি প্রাথমিক পাসের জন্য অনুমান হিসাবে বিবেচনা করেছেন, এটি যথেষ্ট পরিমাণে বড় হতে পারে?
প্রকৌশলী

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

@ ইঞ্জিনিয়ার, আপনার প্রশ্নের উত্তরের নীচে এবং কোডের নীচে সম্বোধন করা হয়েছে। সাব টপিকগুলি সেভাবে পড়তে সহজ করা যায়।
ডগলাস ড্যাসেকো

6

সি ++ 20 std::format

এটা এসে গেছে! বৈশিষ্ট্যটি এখানে বর্ণিত হয়েছে: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0645r9.html এবং পাইথনের মতো .format()বাক্য গঠন ব্যবহার করে।

আমি আশা করি ব্যবহারটি এর মতো হবে:

#include <format>
#include <string>

int main() {
    std::string message = std::format("The answer is {}.", 42);
}

সমর্থনটি জিসিসি, জিসিসি 9.1.0 এ পৌঁছানোর g++-9 -std=c++2aপরেও এটি ব্যবহার না করে চেষ্টা করব।

এপিআই একটি নতুন std::formatশিরোনাম যুক্ত করবে :

প্রস্তাবিত ফর্ম্যাটিং এপিআই নতুন শিরোনামে সংজ্ঞায়িত হয়েছে <format>এবং বিদ্যমান কোডে এর কোনও প্রভাব থাকতে হবে না।

বিদ্যমান fmtগ্রন্থাগারটি আপনার পলিফিলের প্রয়োজন হলে এটি বাস্তবায়নের দাবি করেছে: https://github.com/fmtlib/fmt

সি ++ 20 এর বাস্তবায়ন std::format

এবং এর আগে উল্লেখ করা হয়েছিল: স্প্রিন্টফের মতো স্ট্রিং ফর্ম্যাটিং


5

এরিক অ্যারোনস্টির দেওয়া উত্তরের ভিত্তিতে:

std::string string_format(const std::string &fmt, ...) {
    std::vector<char> str(100,'\0');
    va_list ap;
    while (1) {
        va_start(ap, fmt);
        auto n = vsnprintf(str.data(), str.size(), fmt.c_str(), ap);
        va_end(ap);
        if ((n > -1) && (size_t(n) < str.size())) {
            return str.data();
        }
        if (n > -1)
            str.resize( n + 1 );
        else
            str.resize( str.size() * 2);
    }
    return str.data();
}

এটি তার মূল constফলাফল থেকে দূরে সরে যাওয়ার প্রয়োজন এড়িয়ে যায় .c_str()


1
এরিক অ্যারনেস্টির উত্তরটি বন্ধ করা একটি লাল রঙের হেরিং। লুপটির সাথে তার প্রথম কোডের নমুনাটি অনিরাপদ এবং দ্বিতীয়টি অকার্যকর এবং আনাড়ি। পরিষ্কার বাস্তবায়ন স্পষ্টভাবে ইঙ্গিত করে যে, ফাংশনগুলির কোনও ভিপ্রিন্টফ পরিবারের বুফ_সিজো যদি শূন্য হয় তবে কিছুই লিখিত হয় না এবং বাফার একটি নাল পয়েন্টার হতে পারে, তবে ফেরতের মান (বাইট সংখ্যা যা অন্তর্ভুক্ত নয় এমনটি লেখা হবে) নাল টার্মিনেটর) এখনও গণনা করা হয় এবং ফিরে আসে। : একটি প্রকাশনা গুণমানের উত্তর এখানে stackoverflow.com/questions/2342162/...
ডগলাস Daseeco

আমার যুক্ত হওয়ার পর থেকেই এরিক অ্যারোনস্টির উত্তর সম্পাদনা করা হয়েছে। আমি স্ট্রিংগুলি তৈরি করার সাথে সাথে সংরক্ষণ করতে ভেক্টর <char> ব্যবহারের বিকল্পটি হাইলাইট করতে চেয়েছিলাম। আমি প্রায়শই সি ++ কোড থেকে সি ফাংশন কল করার সময় এই কৌশলটি ব্যবহার করি। এটি আকর্ষণীয় যে প্রশ্নটির এখন 34 টি উত্তর রয়েছে।
চিত্স

Vfprintf পৃষ্ঠায় cppreferences.com উদাহরণটি পরে যুক্ত করা হয়েছিল। আমি বিশ্বাস করি যে সেরা উত্তরটি বর্তমানে গৃহীত উত্তর, একটি প্রিন্টফ বৈকল্পিকের পরিবর্তে স্ট্রিং স্ট্রিম ব্যবহার করা জিনিসগুলির সি ++ উপায়। তবে আমার উত্তরটি যখন সরবরাহ করা হয়েছিল তখন মূল্য যুক্ত করে; এটি অন্যান্য উত্তরগুলির তুলনায় ক্রমান্বয়ে ভাল ছিল। এখন স্ট্যান্ডার্ডটিতে স্ট্রিং_ভিউ, প্যারামিটার প্যাকগুলি এবং ভারিয়াদিক টেম্পলেট রয়েছে একটি নতুন উত্তরে সেই বৈশিষ্ট্যগুলি অন্তর্ভুক্ত থাকতে পারে। আমার জবাব হিসাবে, যদিও এটি এখন অতিরিক্ত আপ-ভোজনের যোগ্য নয়, এটি মুছে ফেলা বা ডাউন-ভোট দেওয়ার উপযুক্ত নয়, তাই আমি এটি হিসাবে রেখে দিচ্ছি।
চিটস

5
inline void format(string& a_string, const char* fmt, ...)
{
    va_list vl;
    va_start(vl, fmt);
    int size = _vscprintf( fmt, vl );
    a_string.resize( ++size );
    vsnprintf_s((char*)a_string.data(), size, _TRUNCATE, fmt, vl);
    va_end(vl);
}

1
স্মার্ট ধারণাটির জন্য +1, তবে এটি কী তা খুব স্পষ্ট নয় _vscprintf। আমি মনে করি আপনার এই উত্তরটি বিস্তারিতভাবে বলা উচিত।
ডাকাভ

3

স্ট্রিংয়ে আপনার যা প্রয়োজন তা নেই, তবে স্ট্যান্ড স্ট্রিমস্ট্রিমটি করে। স্ট্রিংটি তৈরি করতে স্ট্রিংস্ট্রিম ব্যবহার করুন এবং তারপরে স্ট্রিংটি বের করুন। আপনি যে কাজগুলি করতে পারেন তার একটি বিশদ তালিকা এখানে । উদাহরণ স্বরূপ:

cout.setprecision(10); //stringstream is a stream like cout

ডাবল বা ভাসমান প্রিন্ট করার সময় আপনাকে 10 দশমিক দশক যথাযথ স্থান দেবে।


8
যা এখনও আপনাকে কন্ট্রোল প্রিন্টফের কাছ থেকে কিছু দেয় না ... তবে দুর্দান্ত।
এরিক অ্যারোনস্টি

3

আপনি এটি চেষ্টা করতে পারেন:

string str;
str.resize( _MAX_PATH );

sprintf( &str[0], "%s %s", "hello", "world" );
// optionals
// sprintf_s( &str[0], str.length(), "%s %s", "hello", "world" ); // Microsoft
// #include <stdio.h>
// snprintf( &str[0], str.length(), "%s %s", "hello", "world" ); // c++11

str.resize( strlen( str.data() ) + 1 );

3

আপনি যদি এমন কোনও সিস্টেমে থাকেন যা অ্যাসপ্রিন্টফ (3) থাকে তবে আপনি সহজেই এটিকে মোড়ানো করতে পারেন:

#include <iostream>
#include <cstdarg>
#include <cstdio>

std::string format(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));

std::string format(const char *fmt, ...)
{
    std::string result;

    va_list ap;
    va_start(ap, fmt);

    char *tmp = 0;
    int res = vasprintf(&tmp, fmt, ap);
    va_end(ap);

    if (res != -1) {
        result = tmp;
        free(tmp);
    } else {
        // The vasprintf call failed, either do nothing and
        // fall through (will return empty string) or
        // throw an exception, if your code uses those
    }

    return result;
}

int main(int argc, char *argv[]) {
    std::string username = "you";
    std::cout << format("Hello %s! %d", username.c_str(), 123) << std::endl;
    return 0;
}

2
আমি এই লাইনটিকে আগেই ঘোষণা formatহিসাবে যুক্ত করতাম, কারণ এটি জিসিসি-কে তর্কের ধরণগুলি পরীক্ষা করতে এবং -ওয়াল দিয়ে একটি সুনির্দিষ্ট সতর্কতা দেওয়ার জন্য বলে:std::string format(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
অ্যারন

2
আমি স্রেফ একটি কল যুক্ত করেছি va_end"যদি কোনও ফাংশন ভায়_স্টার্ট বা ভিএকপি ফিরে আসে তার আগে যদি ভাই_এন্ডকে না ডাকা হয় তবে আচরণটি অপরিবর্তিত is" - ডক্স
অ্যারন ম্যাকডেইড

1
ব্যর্থতার পরে পয়েন্টারের মান অপরিজ্ঞাত হওয়ার কারণে আপনার ভাসপ্রিন্টফের রিটার্নের ফলাফলটি পরীক্ষা করা উচিত। সুতরাং, সম্ভবত <নতুন> অন্তর্ভুক্ত করুন এবং যুক্ত করুন: যদি (আকার == -1) {নিক্ষেপ করুন :: খারাপ_লোক (); ।
নীল ম্যাকগিল

ভাল কথা, আমি সেই অনুযায়ী উত্তরটি সংশোধন করেছি, আমি সিদ্ধান্ত নেওয়ার পরিবর্তে কেবল সেখানে মন্তব্য করার সিদ্ধান্ত নিয়েছি throw std::bad_alloc();, যেহেতু আমি আমার কোডবেসে সি ++ ব্যতিক্রম ব্যবহার করছি না, এবং যারা করেন তাদের পক্ষে তারা সহজেই এটি ভিত্তিক যুক্ত করতে পারেন উত্স মন্তব্য এবং আপনার মন্তব্য এখানে।
থমাস পার্ল

2

এটি আমার প্রোগ্রামে এটি করার জন্য আমি ব্যবহার করি কোডটি ... এটি অভিনব কিছু নয়, তবে এটি কৌশলটি করে ... নোট, আপনার প্রযোজ্য আকারটি সামঞ্জস্য করতে হবে। আমার জন্য MAX_BUFFER 1024।

std::string Format ( const char *fmt, ... )
{
    char textString[MAX_BUFFER*5] = {'\0'};

    // -- Empty the buffer properly to ensure no leaks.
    memset(textString, '\0', sizeof(textString));

    va_list args;
    va_start ( args, fmt );
    vsnprintf ( textString, MAX_BUFFER*5, fmt, args );
    va_end ( args );
    std::string retStr = textString;
    return retStr;
}

4
টেক্সটস্ট্রিংয়ের সূচনা ইতিমধ্যে পুরো বাফারকে শূন্যে সেট করে।
স্মরণে রাখার

এটি ডেটার একটি সম্পূর্ণ অতিরিক্ত অনুলিপি করে, vsnprintfসরাসরি স্ট্রিংয়ে ব্যবহার করা সম্ভব ।
মাকিং হাঁস

2

ডাকাভ এবং পিক্সেলপয়েন্টের উত্তর থেকে ধারণা নিয়েছেন । আমি কিছুটা খেলেছি এবং এটি পেয়েছি:

#include <cstdarg>
#include <cstdio>
#include <string>

std::string format(const char* fmt, ...)
{
    va_list vl;

    va_start(vl, fmt);
    int size = vsnprintf(0, 0, fmt, vl) + sizeof('\0');
    va_end(vl);

    char buffer[size];

    va_start(vl, fmt);
    size = vsnprintf(buffer, size, fmt, vl);
    va_end(vl);

    return std::string(buffer, size);
}

সঙ্গে বিবেকী প্রোগ্রামিং অনুশীলন আমি বিশ্বাস করি কোড যথেষ্ট হওয়া উচিত, তবে আমি এখনও বেশি নিরাপদ বিকল্প এখনও যথেষ্ট সহজ এবং সি ++ 11 প্রয়োজন হয় না হবে খোলা আছি।


এবং এখানে আর একটি সংস্করণ যা vsnprintf()প্রাথমিক বাফারটি ইতিমধ্যে পর্যাপ্ত পর্যায়ে পর্যাপ্ত হলে দ্বিতীয় কলটি রোধ করতে প্রাথমিক বাফার ব্যবহার করে ।

std::string format(const char* fmt, ...)
{

    va_list vl;
    int size;

    enum { INITIAL_BUFFER_SIZE = 512 };

    {
        char buffer[INITIAL_BUFFER_SIZE];

        va_start(vl, fmt);
        size = vsnprintf(buffer, INITIAL_BUFFER_SIZE, fmt, vl);
        va_end(vl);

        if (size < INITIAL_BUFFER_SIZE)
            return std::string(buffer, size);
    }

    size += sizeof('\0');

    char buffer[size];

    va_start(vl, fmt);
    size = vsnprintf(buffer, size, fmt, vl);
    va_end(vl);

    return std::string(buffer, size);
}

(দেখা যাচ্ছে যে এই সংস্করণটি পিতি ওংমংকোকুলের জবাবের সাথে ঠিক একই রকম , কেবল এটি ব্যবহার করে না newএবং delete[]তৈরি করার সময় একটি আকারও নির্দিষ্ট করে std::string

ধারণা ব্যবহার করছে না এর এখানে newএবং delete[]গাদা উপর স্ট্যাক ব্যবহার পরোক্ষভাবে যেহেতু এটি কল বরাদ্দ এবং deallocation ফাংশন প্রয়োজন নেই, তবে যদি সঠিকভাবে ব্যবহৃত নয়, এটা কিছু (সম্ভবত পুরাতন মধ্যে উপচে বাফার বিপজ্জনক হতে পারে, অথবা সম্ভবত কেবল দুর্বল) সিস্টেম। এই একটি উদ্বেগের বিষয় হয়, তাহলে আমি অত্যন্ত ব্যবহার করার সুপারিশ newএবং delete[]পরিবর্তে। মনে রাখবেন যে এখানে একমাত্র উদ্বেগ হ'ল বরাদ্দ সম্পর্কে vsnprintf()যা ইতিমধ্যে সীমাবদ্ধতার সাথে আহ্বান করা হয়েছে, সুতরাং দ্বিতীয় বাফারে বরাদ্দ করা আকারের উপর ভিত্তি করে একটি সীমা নির্দিষ্ট করাও এগুলি রোধ করতে পারে))


2

আমি সাধারণত এটি ব্যবহার করি:

std::string myformat(const char *const fmt, ...)
{
        char *buffer = NULL;
        va_list ap;

        va_start(ap, fmt);
        (void)vasprintf(&buffer, fmt, ap);
        va_end(ap);

        std::string result = buffer;
        free(buffer);

        return result;
}

অসুবিধা: সমস্ত সিস্টেম ভাসপ্রিন্ট সমর্থন করে না


ভাসপ্রিন্টফটি দুর্দান্ত - তবে আপনাকে রিটার্ন কোডটি পরীক্ষা করতে হবে। অন ​​-1 বাফারের একটি অপরিবর্তিত মান থাকবে। প্রয়োজন: যদি (আকার == -1) {ন্যূনতম :: খারাপ_লোক (); ।
নীল ম্যাকগিল

2

@IFreilicht উত্তরের সামান্য পরিবর্তিত সংস্করণের নীচে, সি ++ 14 এ আপডেট হয়েছে ( make_uniqueকাঁচা ঘোষণার পরিবর্তে ফাংশনের ব্যবহার ) এবং std::stringযুক্তিগুলির জন্য সমর্থন যুক্ত করা হয়েছে (কেনে কেরের নিবন্ধের ভিত্তিতে )

#include <iostream>
#include <memory>
#include <string>
#include <cstdio>

template <typename T>
T process_arg(T value) noexcept
{
    return value;
}

template <typename T>
T const * process_arg(std::basic_string<T> const & value) noexcept
{
    return value.c_str();
}

template<typename ... Args>
std::string string_format(const std::string& format, Args const & ... args)
{
    const auto fmt = format.c_str();
    const size_t size = std::snprintf(nullptr, 0, fmt, process_arg(args) ...) + 1;
    auto buf = std::make_unique<char[]>(size);
    std::snprintf(buf.get(), size, fmt, process_arg(args) ...);
    auto res = std::string(buf.get(), buf.get() + size - 1);
    return res;
}

int main()
{
    int i = 3;
    float f = 5.f;
    char* s0 = "hello";
    std::string s1 = "world";
    std::cout << string_format("i=%d, f=%f, s=%s %s", i, f, s0, s1) << "\n";
}

আউটপুট:

i = 3, f = 5.000000, s = hello world

এই উত্তরটি যদি ইচ্ছা হয় তবে মূলটির সাথে একত্রীকরণে নির্দ্বিধায় থাকুন।


1

পোকো ফাউন্ডেশন লাইব্রেরিতে একটি খুব সুবিধাজনক বিন্যাসের ফাংশন রয়েছে যা স্ট্রিম্যাট স্ট্রিং এবং মান উভয় ক্ষেত্রেই সমর্থন করে:


1

আপনি আইওমানিপ শিরোলেখ ফাইলটি ব্যবহার করে সিউটে সি ++ আউটপুট ফর্ম্যাট করতে পারেন। সেটপ্রেসিশন, সেটফিল ইত্যাদির মতো কোনও সহায়ক ফাংশন ব্যবহার করার আগে আপনি iomanip শিরোনাম ফাইলটি অন্তর্ভুক্ত করেছেন তা নিশ্চিত করুন Make

এখানে ভেক্টরে গড় অপেক্ষার সময় প্রিন্ট করতে আমি অতীতে একটি কোড স্নিপেট ব্যবহার করেছি, যা আমি "সঞ্চিত" করেছি।

#include<iomanip>
#include<iostream>
#include<vector>
#include<numeric>

...

cout<< "Average waiting times for tasks is " << setprecision(4) << accumulate(all(waitingTimes), 0)/double(waitingTimes.size()) ;
cout << " and " << Q.size() << " tasks remaining" << endl;

আমরা কীভাবে সি ++ স্ট্রিমগুলি ফর্ম্যাট করতে পারি তার একটি সংক্ষিপ্ত বিবরণ এখানে। http://www.cprogramming.com/tutorial/iomanip.html


1

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

String.cpp: http://pastebin.com/DnfvzyKP
string.h: http://pastebin.com/7U6iCUMa

String.cpp:

#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <string>

using ::std::string;

#pragma warning(disable : 4996)

#ifndef va_copy
#ifdef _MSC_VER
#define va_copy(dst, src) dst=src
#elif !(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
#define va_copy(dst, src) memcpy((void*)dst, (void*)src, sizeof(*src))
#endif
#endif

///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ap Variable argument list
///
void toString(string &dst, const char *format, va_list ap) throw() {
  int length;
  va_list apStrLen;
  va_copy(apStrLen, ap);
  length = vsnprintf(NULL, 0, format, apStrLen);
  va_end(apStrLen);
  if (length > 0) {
    dst.resize(length);
    vsnprintf((char *)dst.data(), dst.size() + 1, format, ap);
  } else {
    dst = "Format error! format: ";
    dst.append(format);
  }
}

///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ... Variable argument list
///
void toString(string &dst, const char *format, ...) throw() {
  va_list ap;
  va_start(ap, format);
  toString(dst, format, ap);
  va_end(ap);
}

///
/// \breif Format message
/// \param format Format of message
/// \param ... Variable argument list
///
string toString(const char *format, ...) throw() {
  string dst;
  va_list ap;
  va_start(ap, format);
  toString(dst, format, ap);
  va_end(ap);
  return dst;
}

///
/// \breif Format message
/// \param format Format of message
/// \param ap Variable argument list
///
string toString(const char *format, va_list ap) throw() {
  string dst;
  toString(dst, format, ap);
  return dst;
}


int main() {
  int a = 32;
  const char * str = "This works!";

  string test(toString("\nSome testing: a = %d, %s\n", a, str));
  printf(test.c_str());

  a = 0x7fffffff;
  test = toString("\nMore testing: a = %d, %s\n", a, "This works too..");
  printf(test.c_str());

  a = 0x80000000;
  toString(test, "\nMore testing: a = %d, %s\n", a, "This way is cheaper");
  printf(test.c_str());

  return 0;
}

string.h:

#pragma once
#include <cstdarg>
#include <string>

using ::std::string;

///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ap Variable argument list
///
void toString(string &dst, const char *format, va_list ap) throw();
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ... Variable argument list
///
void toString(string &dst, const char *format, ...) throw();
///
/// \breif Format message
/// \param format Format of message
/// \param ... Variable argument list
///
string toString(const char *format, ...) throw();

///
/// \breif Format message
/// \param format Format of message
/// \param ap Variable argument list
///
string toString(const char *format, va_list ap) throw();

লাইনের প্রতি শ্রদ্ধা সহ vsnprintf((char *)dst.data(), dst.size() + 1, format, ap);- স্ট্রিংয়ের বাফারের অবসান নাল চরিত্রের জন্য জায়গা আছে তা ধরে নেওয়া কি নিরাপদ? এমন কি এমন বাস্তবায়ন রয়েছে যা আকার + 1 টি অক্ষর বরাদ্দ করে না? এটি করা কি নিরাপদ হবেdst.resize(length+1); vsnprintf((char *)dst.data(), dst.size(), format, ap); dst.resize(length);
21'16 এ ড্রওয়াটসনকোড

স্পষ্টতই আমার আগের মন্তব্যের উত্তরটি হ'ল: কোনও নাল চরিত্র আছে তা ধরে নেওয়া নিরাপদ নয়। বিশেষত C ++ 98 স্পেসের সাথে: "ডেটাতে মান অ্যাক্সেস করা () + আকার () অপরিজ্ঞাত আচরণ করে : কোনও নাল অক্ষর এই ফাংশনটির দ্বারা ফিরে আসা মান দ্বারা নির্দেশিত অক্ষরের অনুক্রমকে সমাপ্ত করে দেয় এমন কোনও গ্যারান্টি নেই string :: সি_স্টার একটি ফাংশন যা এই ধরণের গ্যারান্টি সরবরাহ করে। একটি প্রোগ্রাম এই অনুক্রমের কোনও বর্ণকেই পরিবর্তন করতে পারে না "" তবে, সি ++ ১১ স্পেসটি নির্দেশ করে dataএবং c_strএটি প্রতিশব্দ।
ড্রওয়াটসনকোড



1

আমি বুঝতে পারি এর উত্তর বহুবার দেওয়া হয়েছে, তবে এটি আরও সংক্ষিপ্ত:

std::string format(const std::string fmt_str, ...)
{
    va_list ap;
    char *fp = NULL;
    va_start(ap, fmt_str);
    vasprintf(&fp, fmt_str.c_str(), ap);
    va_end(ap);
    std::unique_ptr<char[]> formatted(fp);
    return std::string(formatted.get());
}

উদাহরণ:

#include <iostream>
#include <random>

int main()
{
    std::random_device r;
    std::cout << format("Hello %d!\n", r());
}

Http://rextester.com/NJB14150 এও দেখুন


1

আপডেট 1 : যুক্ত fmt::formatটেস্ট

আমি এখানে পদ্ধতি প্রয়োগ করে আমার নিজস্ব তদন্ত নিয়েছি এবং এখানে উল্লিখিত বনামের সাথে বিপরীত ফলাফল অর্জন করেছি।

আমি 4 টি পদ্ধতিতে 4 টি ফাংশন ব্যবহার করেছি:

  • বৈকল্পিক ফাংশন + vsnprintf+ +std::unique_ptr
  • বৈকল্পিক ফাংশন + vsnprintf+ +std::string
  • বৈকল্পিক টেম্পলেট ফাংশন + std::ostringstream+ std::tuple+utility::for_each
  • fmt::formatfmtগ্রন্থাগার থেকে ফাংশন

পরীক্ষার ব্যাকএন্ডের জন্য googletestব্যবহৃত হয়েছে।

#include <string>
#include <cstdarg>
#include <cstdlib>
#include <memory>
#include <algorithm>

#include <fmt/format.h>

inline std::string string_format(size_t string_reserve, const std::string fmt_str, ...)
{
    size_t str_len = (std::max)(fmt_str.size(), string_reserve);

    // plain buffer is a bit faster here than std::string::reserve
    std::unique_ptr<char[]> formatted;

    va_list ap;
    va_start(ap, fmt_str);

    while (true) {
        formatted.reset(new char[str_len]);

        const int final_n = vsnprintf(&formatted[0], str_len, fmt_str.c_str(), ap);

        if (final_n < 0 || final_n >= int(str_len))
            str_len += (std::abs)(final_n - int(str_len) + 1);
        else
            break;
    }

    va_end(ap);

    return std::string(formatted.get());
}

inline std::string string_format2(size_t string_reserve, const std::string fmt_str, ...)
{
    size_t str_len = (std::max)(fmt_str.size(), string_reserve);
    std::string str;

    va_list ap;
    va_start(ap, fmt_str);

    while (true) {
        str.resize(str_len);

        const int final_n = vsnprintf(const_cast<char *>(str.data()), str_len, fmt_str.c_str(), ap);

        if (final_n < 0 || final_n >= int(str_len))
            str_len += (std::abs)(final_n - int(str_len) + 1);
        else {
            str.resize(final_n); // do not forget to shrink the size!
            break;
        }
    }

    va_end(ap);

    return str;
}

template <typename... Args>
inline std::string string_format3(size_t string_reserve, Args... args)
{
    std::ostringstream ss;
    if (string_reserve) {
        ss.rdbuf()->str().reserve(string_reserve);
    }
    std::tuple<Args...> t{ args... };
    utility::for_each(t, [&ss](auto & v)
    {
        ss << v;
    });
    return ss.str();
}

for_each: বাস্তবায়ন এখানে থেকে নেওয়া হয় tuple পুনরুক্তি উপর

#include <type_traits>
#include <tuple>

namespace utility {

    template <std::size_t I = 0, typename FuncT, typename... Tp>
    inline typename std::enable_if<I == sizeof...(Tp), void>::type
        for_each(std::tuple<Tp...> &, const FuncT &)
    {
    }

    template<std::size_t I = 0, typename FuncT, typename... Tp>
    inline typename std::enable_if<I < sizeof...(Tp), void>::type
        for_each(std::tuple<Tp...> & t, const FuncT & f)
    {
        f(std::get<I>(t));
        for_each<I + 1, FuncT, Tp...>(t, f);
    }

}

পরীক্ষাগুলো:

TEST(ExternalFuncs, test_string_format_on_unique_ptr_0)
{
    for (size_t i = 0; i < 1000000; i++) {
        const std::string v = string_format(0, "%s+%u\n", "test test test", 12345);
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_string_format_on_unique_ptr_256)
{
    for (size_t i = 0; i < 1000000; i++) {
        const std::string v = string_format(256, "%s+%u\n", "test test test", 12345);
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_string_format_on_std_string_0)
{
    for (size_t i = 0; i < 1000000; i++) {
        const std::string v = string_format2(0, "%s+%u\n", "test test test", 12345);
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_string_format_on_std_string_256)
{
    for (size_t i = 0; i < 1000000; i++) {
        const std::string v = string_format2(256, "%s+%u\n", "test test test", 12345);
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_string_format_on_string_stream_on_variadic_tuple_0)
{
    for (size_t i = 0; i < 1000000; i++) {
        const std::string v = string_format3(0, "test test test", "+", 12345, "\n");
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_string_format_on_string_stream_on_variadic_tuple_256)
{
    for (size_t i = 0; i < 1000000; i++) {
        const std::string v = string_format3(256, "test test test", "+", 12345, "\n");
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_string_format_on_string_stream_inline_0)
{
    for (size_t i = 0; i < 1000000; i++) {
        std::ostringstream ss;
        ss << "test test test" << "+" << 12345 << "\n";
        const std::string v = ss.str();
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_string_format_on_string_stream_inline_256)
{
    for (size_t i = 0; i < 1000000; i++) {
        std::ostringstream ss;
        ss.rdbuf()->str().reserve(256);
        ss << "test test test" << "+" << 12345 << "\n";
        const std::string v = ss.str();
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_fmt_format_positional)
{
    for (size_t i = 0; i < 1000000; i++) {
        const std::string v = fmt::format("{0:s}+{1:d}\n", "test test test", 12345);
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

TEST(ExternalFuncs, test_fmt_format_named)
{
    for (size_t i = 0; i < 1000000; i++) {
        const std::string v = fmt::format("{first:s}+{second:d}\n", fmt::arg("first", "test test test"), fmt::arg("second", 12345));
        UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
    }
}

UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR

unsued.hpp :

#define UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(var)   ::utility::unused_param(&var)

namespace utility {

    extern const volatile void * volatile g_unused_param_storage_ptr;

    extern void
#ifdef __GNUC__
    __attribute__((optimize("O0")))
#endif
        unused_param(const volatile void * p);

}

unused.cpp :

namespace utility {

    const volatile void * volatile g_unused_param_storage_ptr = nullptr;

    void
#ifdef __GNUC__
    __attribute__((optimize("O0")))
#endif
        unused_param(const volatile void * p)
    {
        g_unused_param_storage_ptr = p;
    }

}

ফলাফল :

[ RUN      ] ExternalFuncs.test_string_format_on_unique_ptr_0
[       OK ] ExternalFuncs.test_string_format_on_unique_ptr_0 (556 ms)
[ RUN      ] ExternalFuncs.test_string_format_on_unique_ptr_256
[       OK ] ExternalFuncs.test_string_format_on_unique_ptr_256 (331 ms)
[ RUN      ] ExternalFuncs.test_string_format_on_std_string_0
[       OK ] ExternalFuncs.test_string_format_on_std_string_0 (457 ms)
[ RUN      ] ExternalFuncs.test_string_format_on_std_string_256
[       OK ] ExternalFuncs.test_string_format_on_std_string_256 (279 ms)
[ RUN      ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_0
[       OK ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_0 (1214 ms)
[ RUN      ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_256
[       OK ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_256 (1325 ms)
[ RUN      ] ExternalFuncs.test_string_format_on_string_stream_inline_0
[       OK ] ExternalFuncs.test_string_format_on_string_stream_inline_0 (1208 ms)
[ RUN      ] ExternalFuncs.test_string_format_on_string_stream_inline_256
[       OK ] ExternalFuncs.test_string_format_on_string_stream_inline_256 (1302 ms)
[ RUN      ] ExternalFuncs.test_fmt_format_positional
[       OK ] ExternalFuncs.test_fmt_format_positional (288 ms)
[ RUN      ] ExternalFuncs.test_fmt_format_named
[       OK ] ExternalFuncs.test_fmt_format_named (392 ms)

আপনি দেখতে পাচ্ছেন যে এর মাধ্যমে বাস্তবায়ন vsnprintf+ std::stringএর সমান fmt::format, তবে vsnprintf+ এর মাধ্যমে দ্রুত std::unique_ptr, যা এর মধ্য দিয়ে দ্রুত std::ostringstream

পরীক্ষাগুলি সংকলিত Visual Studio 2015 Update 3এবং চালানো হয় Windows 7 x64 / Intel Core i7-4820K CPU @ 3.70GHz / 16GB

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.