Используйте строки формата, которые содержат% 1,% 2 и т. Д. Вместо% d,% s и т. Д. - Linux, C ++ - PullRequest
3 голосов
/ 26 декабря 2010

В качестве продолжения этого вопроса (замена компилятора сообщений в Linux gcc) у меня возникла следующая проблема:

При использовании MC.exe в Windows для компиляции и генерации сообщений в коде C ++ я вызываю FormatMessage, который получает сообщение и использует параметр va_list *Arguments для отправки различных аргументов сообщения. Например:
Файл messages.mc:

MessageId=1
Severity=Error
SymbolicName=MULTIPLE_MESSAGE_OCCURED
Language=English
message %1 occured %2 times.
.

C ++ код:

void GetMsg(unsigned int errCode, wstring& message,unsigned int paramNumber, ...)
{   
    HLOCAL msg;
    DWORD ret;
    LANGID lang = GetUserDefaultLangID();
    try
    {
        va_list argList;
        va_start( argList, paramNumber );
        const TCHAR* dll = L"MyDll.dll";
        _hModule = GetModuleHandle(dll);
        ret =::FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_IGNORE_INSERTS,
            _hModule,
            errCode,
            lang,
            (LPTSTR) &msg,
            0,
            &argList );
        if ( 0 != ret )
        {
            unsigned int count = 0 ;
            message = msg;
            if (paramNumber>0)
            {
                wstring::const_iterator iter;
                for (iter = message.begin();iter!=message.end();iter++)
                {
                    wchar_t xx = *iter;
                    if (xx ==L'%')
                        count++;
                }
            }
            if ((count == paramNumber) && (count >0))
            {

                ::LocalFree( msg );
                ret =::FormatMessage(
                    FORMAT_MESSAGE_ALLOCATE_BUFFER |
                    FORMAT_MESSAGE_FROM_HMODULE,
                    _hModule,
                    errCode,
                    GetUserDefaultLangID(),
                    (LPTSTR) &msg,
                    0,
                    &argList );
            }
            else if (count != paramNumber)
            {
                wstringstream tmp;
                wstring messNumber;
                tmp << (errCode & 0xFFFF);
                tmp >> messNumber;
                message = message +L"("+ messNumber + L"). Bad Format String. ";
            }
        }
        ::LocalFree( msg );
    }
    catch (...)
    {
        message << L"last error: " << GetLastError();
    }
    va_end( argList );
}

Код звонящего:

wstring message;
GetMsg(MULTIPLE_MESSAGE_OCCURED, message,2, "Error message", 5);

Теперь я написал простой сценарий для создания файла .msg из файла .mc, а затем использую gencat для создания из него каталога.

Но есть ли способ использовать отформатированные строки, поскольку они содержат% 1,% 2 и т. Д., А НЕ общий (% d,% s ...) формат?

Обратите внимание, что решение должно быть достаточно общим для каждого возможного сообщения с каждым возможным типом \ порядком аргументов ...

Возможно ли это вообще?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 26 декабря 2010

Прежде всего функции, такие как printf, поддерживают позиционированный формат:

printf("%2$s, %1$d", salary, name);

Для C ++, кроме решения C, есть библиотека boost::format:

std::cout << boost::format("%2%, %1%") % salary % name;

Также, если выПеремещение программного обеспечения в Linux Я бы предложил использовать «другой» подход для локализации: использовать либо библиотеку gettext, либо boost.locale.

И вместо этого:

wstring message;
GetMsg(MULTIPLE_MESSAGE_OCCURED, message,2, "Error message", 5);

Использование:

C / gettext:

snprintf(msg,sizeof(msg),gettext("This is the message to %1$s about %2$s"),who,what);

C ++ / gettext:

using boost::format;
std::ostringstream ss;
ss << format(gettext("This is the message to %1% about %2%")) % who % what;

C ++ с использованием boost.locale:

using boost::locale::format;
using boost::locale::translate;
std::ostringstream ss;
ss << format(translate("This is the message to {1} about {2}")) % who % what;
0 голосов
/ 26 декабря 2010

Проблема с позиционными параметрами, такими как% 1 $ anytype, заключается в том, что должен появиться в строке формата для работы% 2 $ anytype. Ср printf("Today, %1$s received %2$d dollars in salary\n", name, salary); против printf("Today, I received %2$d dollars in salary\n", name, salary); (бум). Так что это не всегда работает, например, когда пользователь может предоставить строку формата и решает опустить поле. В этом случае подход с именованными параметрами кажется предпочтительным. Например, libHX предоставляет такие, где вы можете использовать "%(SALARY) %(NAME)".

0 голосов
/ 26 декабря 2010

Функция FormatMessage () использует спецификаторы формата в стиле printf; они идут внутри восклицательных знаков после% 1 или чего-то еще. Заполнитель без спецификатора формата эквивалентен printf "% s."

Что вам нужно сделать, это немного преобразовать строки формата; измените "% 1" на "% 1 $ s", "% 2! u!" на "% 2 $ u", "% 3! 4.5e!" до "% 3 $ 4.5e" и так далее. В основном просто поменять! символы вокруг спецификатора формата в один $, предшествующий ему, и справляются с возможностью простого числа%.

...