2015-10-07 2 views
0

Я хотел бы извлечь информацию типа C++ из строки формата printf. Например,Извлечение информации о типе из строки формата printf

Input: "%10u foo %% %+6.3f %ld %s" 

Output: 
    unsigned int 
    double 
    long 
    char* 

Я попытался это с помощью parse_printf_format() из printf.h, но возвращаемый argtypes, похоже, не включает в себя информацию о подписи/без знака.

Есть ли способ получить подписанную/неподписанную информацию?

+0

Это, кажется, очень легко сделать вручную. Помните, однако, что нет никакого сопоставления 1: 1 между символом и типом, потому что, например, float повышается до double при передаче через va_args или /, и вы можете печатать float через «% g» или «% f» или «% a »и т. д. Это также зависит от платформы, на которой вы находитесь (% I64d для Windows, но% lld для linux) – xryl669

+0

@ xryl669 Спасибо за комментарий. Я нахожусь в Linux и не забочусь о поддержке любой другой платформы. Когда вы говорите, что это легко сделать вручную, вы предлагаете анализировать строковый символ по символу без использования таких функций, как parse_printf_format()? – dshin

+0

Можете ли вы уточнить свою потребность в использовании для этой информации немного? Есть шанс, что может быть гораздо лучший подход, чем синтаксический анализ строк printf. –

ответ

1

Как я уже сказал в своем ответе, parse_printf_format создан не для того, что вам нужно. Вы можете разобрать его самостоятельно, с помощью этого алгоритма:

  1. Поскольку символ после % либо модификатор или типа (не может быть одновременно), вы первый поиск % полукокса в строке
  2. Если следующий символ является в массиве типов ('d', 's', 'f', 'g', 'u' и т. д.), тогда вы получаете класс типа (указатель, int, unsigned, double и т. д. ..). Этого может быть достаточно для того, что вам нужно.
  3. Если нет, то вы продолжаете следующий символ, пока не найдете один символ, который не допускается в массиве модификатора/типа.
  4. Если класса для этого типа недостаточно для ваших нужд, вам нужно будет вернуться к модификатору, чтобы настроить конечный тип.

Вы можете использовать множество реализаций для подлинного алгоритма (например boost), но так как вам не нужно, чтобы проверить строку ввода, это очень просто сделать вручную.

псевдокод:

const char flags[] = {'-', '+', '0', ' ', '#'}; 
const char widthPrec[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '*'}; // Last char is an extension 
const char modifiers[] = { 'h', 'l', 'L', 'z', 'j', 't' }; 
const char types[] = { '%', 'd', 'i', 'u', 'f', 'F', 'e', 'E', 'g', 'G', 'x', 'X', 'a', 'A', 'o', 's', 'c', 'p', 'n' }; // Last one is not wanted too 

const char validChars[] = { union of all arrays above }; 

enum Type { None = 0, Int, Unsigned, Float, etc... }; 
Type typesToType[] = { None, Int, Int, Unsigned, Float, Float, ... etc... }; // Should match the types array above 

// Expect a valid format, not validation is done 
bool findTypesInFormat(string & format, vector<Type> types) 
{ 
    size_t pos = 0; 
    types.clear(); 
    while (pos < format.length()) 
    { 
     pos = format.find_first_of('%', pos); 
     if (pos == format.npos) break; 
     pos++; 
     if (format[pos] == '%') continue; 
     size_t acceptUntilType = format.find_first_not_of(validChars, pos); 
     if (pos == format.npos) pos = format.length(); 
     pos --; 
     if (!inArray(types, format[pos])) return false; // Invalid string if the type is not what we support 

     Type type = typesToType[indexInArray(types, format[pos])]; 

     // We now know the type, we might need to refine it 
     if (inArray(modifiers, format[pos-1]) 
     { 
      type = adjustTypeFromModifier(format[pos-1], type); 
     } 
     types.push_back(type); 
     pos++; 
    } 
    return true; 
} 

// inArray, indexInArray and adjustTypeFromModifier are simple functions left to be written. 
+0

Спасибо, это работает. – dshin

Смежные вопросы