سؤال

البحث عن تطبيق لـ C++ لوظيفة مثل String.Format الخاصة بـ .NET.من الواضح أن هناك printf وأصنافها، لكنني أبحث عن شيء موضعي كما في:

String.Format("مرحبًا {0}.عمرك {1} سنة.كيف تشعر أن تكون {1}؟ "، الاسم ، العمر) ؛

يعد ذلك ضروريًا لأننا سنحاول جعل تعريب تطبيقنا أسهل، كما أن منح المترجمين {0} و{1} لتحديد موضعهم في أي مكان في الجملة أسهل بكثير من منحهم %s، %d، % d والتي يجب وضعها بهذا الترتيب في ترجمتها.

أفترض أن البحث والاستبدال بمدخلات متغيرة (va_start، va_end، وما إلى ذلك) هو ما سأنتهي من بناءه، ولكن إذا كان هناك حل قوي بالفعل، فسيكون ذلك هو الأفضل.

شكرًا :)

هل كانت مفيدة؟

المحلول 6

والكثير من توصيات جيدة فوق ذلك سوف تعمل في معظم الحالات. في حالتي، كنت أرغب في نهاية المطاف إلى تحميل سلاسل من الموارد، والحفاظ على الموارد سلسلة أقرب إلى صافي String.Format ما استطعت، لذلك أنا تدحرجت بلدي. بعد النظر في بعض تطبيقات أعلاه لأفكار، وتنفيذ الناتجة قصيرة جدا وسهلة.

وهناك سلسلة الطبقة التي في حالتي مستمد من مايكروسوفت CString، ولكنه يمكن أن تجنيها من حول أي فئة السلسلة. وهناك أيضا StringArg الدرجة - انها مهمة هي أن تأخذ أي نوع المعلمة وتحويلها إلى سلسلة (أي أنه يحاكي ToString في .NET). إذا كان يحتاج الكائن الجديد الذي سيتم ToString'd، يمكنك فقط إضافة منشئ آخر. منشئ يسمح شكل محدد على غرار printf لتنسيق غير افتراضي.

والطبقة سلسلة ثم يقبل معرف جدول سلسلة لسلسلة مصدر، وعدد من المعلمات StringArg، وأخيرا HINSTANCE اختياري (I استخدام الكثير من دلس، أي من الذي يمكن أن استضافة جدول سلسلة، لذلك هذا سمح لي بالمرور في ذلك، أو استخدام HINSTANCE-DLL محدد افتراضيا).

وأمثلة الاستخدام:

dlg.m_prompt = String(1417); //"Welcome to Stackoverflow!"
MessageBox(String(1532, m_username)); //"Hi {0}"

وكما هو الحال، فإنه يأخذ فقط ID سلسلة لمدخلا، ولكن سيكون تافها لإضافة سلسلة الإدخال بدلا من ID سلسلة:

CString s = String.Format("Hi {0}, you are {1} years old in Hexidecimal", m_userName, StringArg(m_age, "%0X"));

والآن لفئة StringArg الذي لا يعادل ToString على متغيرات:

class StringArg
{
StringArg(); //not implemented
        StringArg(const StringArg&); //not implemented
        StringArg& operator=(const StringArg&); //not implemented

    public:
        StringArg(LPCWSTR val);
    StringArg(const CString& val);
    StringArg(int val, LPCWSTR formatSpec = NULL);
    StringArg(size_t val, LPCWSTR formatSpec = NULL);
    StringArg(WORD val, LPCWSTR formatSpec = NULL);
    StringArg(DWORD val, LPCWSTR formatSpec = NULL);
    StringArg(__int64 val, LPCWSTR formatSpec = NULL);
    StringArg(double val, LPCWSTR formatSpec = NULL);
    CString ToString() const;
private:
    CString m_strVal;
};

extern HINSTANCE GetModuleHInst(); //every DLL implements this for getting it's own HINSTANCE -- scenarios with a single resource DLL wouldn't need this

لفئة سلسلة، وهناك مجموعة من وظائف الأعضاء والمنشئات التي تستغرق ما يصل إلى 10 الحجج. هذه الكلمة في نهاية المطاف CentralFormat التي لا العمل الحقيقي.

class String : public CString
{
public:
    String() { }
    String(WORD stringTableID, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, hInst); }
    String(WORD stringTableID, const StringArg& arg1, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, hInst); }
    String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, hInst); }
    String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, hInst); }
    String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, hInst); }
    String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, hInst); }
    String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, arg6, hInst); }
    String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, hInst); }
    String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, hInst); }
    String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, const StringArg& arg9, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, hInst); }


    CString& Format(WORD stringTableID, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, HINSTANCE hInst = GetModuleHInst());
    CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, const StringArg& arg9, HINSTANCE hInst = GetModuleHInst());
private:
    void CentralFormat(WORD stringTableID, std::vector<const StringArg*>& args, HINSTANCE hInst);
};

وأخيرا، وتنفيذ (أمل انه موافق على إضافة هذا بكثير على ستاكوفيرفلوو، على الرغم من أن الجزء الأكبر من ذلك هو بسيط جدا):

StringArg::StringArg(LPCWSTR val)
{
    m_strVal = val;
}

StringArg::StringArg(const CString& val)
{
    m_strVal = (LPCWSTR)val;
}

StringArg::StringArg(int val, LPCWSTR formatSpec)
{
    if(NULL == formatSpec)
        formatSpec = L"%d"; //GLOK
    m_strVal.Format(formatSpec, val);
}

StringArg::StringArg(size_t val, LPCWSTR formatSpec)
{
    if(NULL == formatSpec)
        formatSpec = L"%u"; //GLOK
    m_strVal.Format(formatSpec, val);
}

StringArg::StringArg(WORD val, LPCWSTR formatSpec)
{
    if(NULL == formatSpec)
        formatSpec = L"%u"; //GLOK
    m_strVal.Format(formatSpec, val);
}

StringArg::StringArg(DWORD val, LPCWSTR formatSpec)
{
    if(NULL == formatSpec)
        formatSpec = L"%u"; //GLOK
    m_strVal.Format(formatSpec, val);
}

StringArg::StringArg(__int64 val, LPCWSTR formatSpec)
{
    if(NULL == formatSpec)
        formatSpec = L"%I64d"; //GLOK
    m_strVal.Format(formatSpec, val);
}

StringArg::StringArg(double val, LPCWSTR formatSpec)
{
    if(NULL == formatSpec)
        formatSpec = L"%f"; //GLOK
    m_strVal.Format(formatSpec, val);
}

CString StringArg::ToString() const
{ 
    return m_strVal; 
}


void String::CentralFormat(WORD stringTableID, std::vector<const StringArg*>& args, HINSTANCE hInst)
{
    size_t argsCount = args.size();
    _ASSERT(argsCount < 10); //code below assumes a single character position indicator

    CString tmp;
    HINSTANCE hOld = AfxGetResourceHandle();
    AfxSetResourceHandle(hInst);
    BOOL b = tmp.LoadString(stringTableID);
    AfxSetResourceHandle(hOld);
    if(FALSE == b)
    {
#ifdef _DEBUG

        //missing string resource, or more likely a bad stringID was used -- tell someone!!
    CString s;
        s.Format(L"StringID %d could not be found!  %s", stringTableID, hInst == ghCommonHInst ? L"CommonHInst was passed in" : L"CommonHInst was NOT passed in"); //GLOK
        ::MessageBeep(MB_ICONHAND);
        ::MessageBeep(MB_ICONEXCLAMATION);
        ::MessageBeep(MB_ICONHAND);
        _ASSERT(0);
        ::MessageBox(NULL, s, L"DEBUG Error - Inform Development", MB_ICONSTOP | MB_OK | MB_SERVICE_NOTIFICATION); //GLOK
        }
#endif //_DEBUG

    CString::Format(L"(???+%d)", stringTableID); //GLOK
        return;
    }

    //check for the degenerate case
    if(0 == argsCount)
    {
        CString::operator=(tmp);
        return;
    }

    GetBuffer(tmp.GetLength() * 3); //pre-allocate space
    ReleaseBuffer(0);
    LPCWSTR pStr = tmp;
    while(L'\0' != *pStr)
    {
        bool bSkip = false;

        if(L'{' == *pStr)
        {
            //is this an incoming string position?
            //we only support 10 args, so the next char must be a number
            if(wcschr(L"0123456789", *(pStr + 1))) //GLOK
            {
                if(L'}' == *(pStr + 2)) //and closing brace?
                {
                    bSkip = true;

                    //this is a replacement
                    size_t index = *(pStr + 1) - L'0';
                    _ASSERT(index < argsCount);
                    _ASSERT(index >= 0);
                    if((index >= 0) && (index < argsCount))
                        CString::operator+=(args[index]->ToString());
                    else
                    {
//bad positional index

                        CString msg;
                        msg.Format(L"(??-%d)", index); //GLOK
                        CString::operator+=(msg);
                    }
                    pStr += 2; //get past the two extra characters that we skipped ahead and peeked at
                }
            }
        }

        if(false == bSkip)
            CString::operator+=(*pStr);
        pStr++;
    }
}


CString& String::Format(WORD stringTableID, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    args.push_back(&arg2);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    args.push_back(&arg2);
    args.push_back(&arg3);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    args.push_back(&arg2);
    args.push_back(&arg3);
    args.push_back(&arg4);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    args.push_back(&arg2);
    args.push_back(&arg3);
    args.push_back(&arg4);
    args.push_back(&arg5);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    args.push_back(&arg2);
    args.push_back(&arg3);
    args.push_back(&arg4);
    args.push_back(&arg5);
    args.push_back(&arg6);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    args.push_back(&arg2);
    args.push_back(&arg3);
    args.push_back(&arg4);
    args.push_back(&arg5);
    args.push_back(&arg6);
    args.push_back(&arg7);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    args.push_back(&arg2);
    args.push_back(&arg3);
    args.push_back(&arg4);
    args.push_back(&arg5);
    args.push_back(&arg6);
    args.push_back(&arg7);
    args.push_back(&arg8);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, const StringArg& arg9, HINSTANCE hInst)
{
    std::vector<const StringArg*> args;
    args.push_back(&arg1);
    args.push_back(&arg2);
    args.push_back(&arg3);
    args.push_back(&arg4);
    args.push_back(&arg5);
    args.push_back(&arg6);
    args.push_back(&arg7);
    args.push_back(&arg8);
    args.push_back(&arg9);
    CentralFormat(stringTableID, args, hInst);
    return *this;
}

نصائح أخرى

QString

وQT يسمح لك القيام به لهذا:

QString("Hi there %1. You are %2 years old. How does it feel \
         to be %2?").arg(name).arg(age)

وصدقوا أو لا تصدقوا، printf والأصدقاء دعم الحجج الموضعية.

 #include <stdio.h>

 int main() {
   char *name = "Logan";
   int age = 25;
   printf("Hi there %1$s, you are %2$d years old. How does it feel to be %2$d?\n", name, age);
  return 0;
 }

قد يكون لديك نظرة على FastFormat -library.

واعتقد انه يمكن استخدام FastFormat ، و

std::string result;

fastformat::fmt(result, "Hi there {0}. You are {1} years old. How does it feel to be {1}?", name, age);

والذي يكاد يكون بناء الجملة متطابقة.

العديد من الخيارات:

  • تعزيز مكتبة التنسيق (سبق ذكرها)
  • com.stringstreams
  • وظائف printf/sprintf القديمة
  • التنفيذ المخصص باستخدام التعبيرات العادية أو وظائف السلسلة المضمنة

وفي ملاحظة ذات صلة، ما تتحدث عنه غير مناسب تمامًا للتوطين.

وiostream:

stringstream s;
string a;
s << "this is string a: " << a << endl;

ويمكنك تنسيق مثل sprintf (جوجل ل "تنسيق iostream") وفي مستوى C ++.

إذا كنت تريد الذهاب لتكون الكتابة الخاصة بك، بحث واستبدال ربما لا يكون أفضل النهج، لأن معظم بحث / استبدال أساليب تسمح فقط يمكنك استبدال واحدة في وقت واحد، والقيام بعمل سيئة للغاية السماح escpae حرفا ( مثل إذا كنت ترغب في تضمين {0} سلسلة حرفية في الإخراج.

وكنت أفضل حالا كتابة آلة المحدودة للدولة الخاصة بك على المشي من خلال سلسلة الإدخال، وتوليد سلسلة الانتاج على الطاير في مرور واحد. وهذا يسمح لك للتعامل مع هروب الشخصيات وظائف الإخراج أكثر تعقيدا (مثل التواريخ المحلية {0:dd\MM\yyyy} على سبيل المثال). وسوف تعطيك بطريقة أكثر مرونة بالإضافة إلى كونها أسرع من بحث / استبدال أو نهج التعابير المنطقية.

وتستهدف ويندوز؟ FormatMessage () هو صديقك

إذا يجب أن يكون شاملا للمنهاج، ثم أود أن التصويت لدفعة :: الشكل، أو ربما وحدة العناية المركزة. إذا يجب عليك فقط تدعم ويندوز، ثم FormatMessage (أو المجمع مريحة من ذلك، CString :: FormatMessage، إذا كنت تستخدم MFC)

هل نلقي نظرة هنا للمقارنة: HTTP: // شبكة الاتصالات العالمية. mihai-nita.net/article.php؟artID=20060430a

منذ بعض الوقت، كنت أحاول أن أفعل شيئًا كهذا، ولكن مع بعض الافتراضات الإضافية:

  • لا يوجد دعم للتنسيق الموضعي (لذا أعتقد أنه لا يناسبك)
  • c++2k3 (لتتمكن من دمجه مع بعض الأكواد القديمة)
  • (تقريبًا) لا توجد تبعيات (حتى crt، لذا لا توجد تبعيات sprintf)

لقد فشلت في ذلك، وهو غير مكتمل تمامًا، ولكن لا يزال بإمكانك إلقاء نظرة على بعض النتائج:

http://code.google.com/p/pileofcrap/source/browse/tests_format.cpp

http://code.google.com/p/pileofcrap/source/browse/format/Format.h

وبالإضافة إلى الخيارات المقترحة من قبل الآخرين ويمكنني أن أوصى معاهدة المواد الانشطارية المكتبة التي تنفذ سلسلة تنسيق مشابهة ل str.format في بيثون وString.Format في C #. وإليك مثال:

string result = fmt::format("Hi {0}. You are {1} years old.", name, age);

والمكتبة هي تماما اكتب آمنة وغير أسرع بكثير من تنسيق دفعة.

تنويه: أنا صاحب هذا مكتبة

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top