Акцентированные / умные символы в C? - PullRequest
4 голосов
/ 12 ноября 2009

Я только что узнал о C и получил задание, в котором мы должны перевести простой текст в азбуку Морзе и обратно. (Я в основном знаком с Java, поэтому терпите меня по поводу используемых мной терминов).

Для этого у меня есть массив со строками для всех букв.

char *letters[] = {
".- ", "-... ", "-.-. ", "-.. ", ".", "..-." etc

Я написал функцию для возврата позиции нужной буквы.

int letter_nr(unsigned char c)
{
    return c-97;
}

Это работает, но спецификации назначения требуют обработки шведских умаленных букв ääö. Шведский алфавит такой же, как английский с этими тремя буквами в конце. Я попытался проверить это, вот так:

int letter_nr(unsigned char c)
{
    if (c == 'å')
        return 26;
    if (c == 'ä')
        return 27;
    if (c == 'ö')
        return 28;
    return c-97;
}

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

int main()
{   
    unsigned char letter;

    while(1)
    {
        printf("Type a letter to get its position: ");
        scanf("%c", &letter);
        printf("%d\n", letter_nr(letter));
    }
    return 0;
}

Что я могу сделать, чтобы решить эту проблему?

Ответы [ 3 ]

10 голосов
/ 12 ноября 2009

Кодировка символьных констант фактически зависит от ваших настроек локали.

Самый безопасный вариант - использовать широкие символы и соответствующие функции. Вы объявляете алфавит const wchar_t* alphabet = L"abcdefghijklmnopqrstuvwxyzäöå", а отдельные символы - L'ö';

Эта небольшая программа-пример работает для меня (также на консоли UNIX с UTF-8) - попробуйте.

#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(int argc, char** argv)
{
    wint_t letter = L'\0';
    setlocale(LC_ALL, ""); /* Initialize locale, to get the correct conversion to/from wchars */
    while(1)
    {
        if(!letter)
            printf("Type a letter to get its position: ");

        letter = fgetwc(stdin);
        if(letter == WEOF) {
        putchar('\n');
        return 0;
        } else if(letter == L'\n' || letter == L'\r') { 
        letter = L'\0'; /* skip newlines - and print the instruction again*/
        } else {
        printf("%d\n", letter); /* print the character value, and don't print the instruction again */
        }
    }
    return 0;
}

Пример сеанса:

Type a letter to get its position: a
97
Type a letter to get its position: A
65
Type a letter to get its position: Ö
214
Type a letter to get its position: ö
246
Type a letter to get its position: Å
197
Type a letter to get its position: <^D>

Я понимаю, что в Windows это не работает с символами вне BMP Unicode, но здесь это не проблема.

2 голосов
/ 12 ноября 2009

Вообще кодирование довольно сложное. С другой стороны, если вам просто нужно грязное решение, специфичное для вашего компилятора / платформы, добавьте что-то подобное в свой код:

printf("letter 0x%x is number %d\n", letter, letter_nr(letter));

Это даст шестнадцатеричное значение для ваших умляутов. Чем просто заменить в if заявлениях ваше письмо с номером.

РЕДАКТИРОВАТЬ Вы говорите, что всегда получаете 98, поэтому ваш сканф получил 98 + 97 = 195 = 0x3C с консоли. В соответствии с этой таблицей 0x3C является начало последовательности UTF8 для общего МАЛЕНЬКОГО ЛАТИНСКОГО БУКВЫ N С Нечто в Latin1 block. Вы находитесь на Mac OS X?

РЕДАКТИРОВАТЬ Это мой последний звонок. Довольно хакерство, но у меня это работает :)

#include <stdio.h>

// scanf for for letter. Return position in Morse Table. 
// Recognises UTF8 for swedish letters.
int letter_nr()
{
  unsigned char letter;
  // scan for the first time,
  scanf("%c", &letter);
  if(0xC3 == letter)
  {
    // we scanf again since this is UTF8 and two byte encoded character will come
    scanf("%c", &letter);
    //LATIN SMALL LETTER A WITH RING ABOVE = å
    if(0xA5 == letter)
      return 26;
    //LATIN SMALL LETTER A WITH DIAERESIS = ä
    if(0xA4 == letter)
      return 27;
   // LATIN SMALL LETTER O WITH DIAERESIS = ö
    if(0xB6 == letter)
      return 28;

    printf("Unknown letter. 0x%x. ", letter);
    return -1;
  } 
  // is seems to be regular ASCII
  return letter - 97;
 } // letter_nr

int main()
{   
    while(1)
    {
        printf("Type a letter to get its position: ");

        int val = letter_nr();
        if(-1 != val)
          printf("Morse code is %d.\n", val);
        else
          printf("Unknown Morse code.\n");

        // strip remaining new line
    unsigned char new_line;
    scanf("%c", &new_line);         
    }
    return 0;
}
0 голосов
/ 13 ноября 2009

Хммм ... сначала я бы сказал, что "забавные" персонажи не char с. Вы не можете передать один из них функции, принимающей аргумент char, и ожидать, что она будет работать.

Попробуйте это (добавить оставшиеся биты):

char buf[100];
printf("Enter a string with funny characters: ");
fflush(stdout);
fgets(buf, sizeof buf, stdin);
/* now print it, as if it was a sequence of `char`s */
char *p = buf;
while (*p) {
    printf("The character '%c' has value %d\n", *p, *p);
    p++;
}

Теперь попробуйте то же самое с широкими символами: #include <wchar.h> и замените printf на wprintf, fgets на fgetws и т. Д. *

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