% s минимальная ширина поля при наличии символов Юникод - PullRequest
2 голосов
/ 30 апреля 2020

Итак, вот моя проблема:

Если кто-то хочет выводить визуально выровненные строки, используя printf, он, очевидно, будет использовать %<n>s (где <n> - минимальная ширина поля). И это прекрасно работает, если только одна из строк не содержит символов Unicode (UTF-8).

Возьмем этот базовый c пример:

#include <stdio.h>

int main(void)
{
    char* s1 = "\u03b1\u03b2\u03b3";
    char* s2 = "abc";

    printf("'%6s'\n", s1);
    printf("'%6s'\n", s2);

    return 0;
}

, который выдаст следующий вывод :

'αβγ'
'   abc'

Это не так уж удивительно, потому что printf, конечно, не знает, что \u03b1 (который состоит из двух символов) создает только один глиф на устройстве вывода (при условии UTF- Поддерживается 8).

Теперь предположим, что я генерирую s1 и s2, но не контролирую строку формата, используемую для вывода этих переменных. В настоящее время я понимаю, что ничего, что я мог бы сделать, чтобы s1 не смогло бы это исправить, потому что мне пришлось бы каким-то образом обмануть printf, думая, что s1 короче, чем есть на самом деле. Однако, так как я также управляю s2, мое текущее решение состоит в том, чтобы добавить непечатаемый символ к s2 для каждого символа Unicode в s1, что будет выглядеть примерно так:

#include <stdio.h>

int main(void)
{
    char* s1 = "\u03b1\u03b2\u03b3";
    char* s2 = "abc\x06\x06\x06";

    printf("'%6s'\n", s1);
    printf("'%6s'\n", s2);

    return 0;
}

Это даст желаемый результат (даже если фактическая ширина больше не соответствует указанной ширине поля, но я готов принять это):

'αβγ'
'abc'

Для контекста:

Приведенный выше пример служит только для иллюстрации проблемы с юникодом, мой настоящий код включает печать чисел с префиксами SI, только один из которых (µ) является символом юникода. Поэтому я буду генерировать строки, содержащие не более одного нормального символа или символа Юникод (поэтому я могу принять результирующее смещение в ширину поля).

Итак, мои вопросы:

  • Есть ли лучшее решение для этого?
  • Является ли \x06 (ACK) разумным выбором (т. Е. Персонаж без нежелательных побочных эффектов)?
  • Можете ли вы вспомнить какие-либо проблемы с такой подход?

1 Ответ

0 голосов
/ 30 апреля 2020

Так как non ascii ограничено µ, я думаю, что есть решение. Я принял значение µ равным \u00b5. Замените его на правильное значение

Я кодировал небольшую функцию myPrint, которая принимает на вход строку и ширину n. Вы сможете изменить приведенный ниже код в соответствии с вашими потребностями.

Функция ищет все вхождения µ и увеличивает эту ширину до строки

#include <stdio.h>

void myPrint(char* string, int n)
{
  char* valueOfNu = "\u00b5";
  for(int i=0;string[i]!='\0';i++)
  {
    if(string[i]==valueOfNu[0] && string[i+1]==valueOfNu[1])
      n++;
  }

  printf("%*s",n,string);
}


int main(void)
{
    char* s1 = "ab\u00b5";
    char* s2 = "abc";

    myPrint(s1,6);
    printf("\n");
    myPrint(s2,6);
    printf("\n");

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...