views:

284

answers:

4

This is a follow-up to my previous question . I succeeded in implementing the algorithm for checking umlauted characters. The next problem comes from iterating over all characters in a string. I do this like so:

int main()
{
    char* str = "Hej du kalleåäö";
    printf("length of str: %d", strlen(str));

    for (int i = 0; i < strlen(str); i++)
    {
     printf("%s ", to_morse(str[i]));
    }
    putchar('\n');
    return 0;
}

The problem is that, because of the umlauted characters, it prints 18, and also makes the to_morse function fail (ignoring these characters). The toMorse method accepts an unsigned char as a parameter. What would be the best way to solve this? I know I can check for the umlaut character here instead of the letterNr function but I don't know if that would be a pretty/logical solution.

+3  A: 

Normally, you'd store the string in a wchar_t and use something like ansi_strlen to get the length of it - that would give you the number of printed characters as opposed to the number of bytes you stored.

You really shouldn't be implementing UTF or Unicode or whatever multibyte character handling yourself - there are libraries for that sort of thing.

Carl Smotricz
I am not familiar with the libraries (coming from the Java world). I implemented Michal Sznajder's hack for these chars so I was hoping there would be a solution similar to this as well.
pg-robban
This may be all you need: http://www.tablix.org/~avian/blog/archives/2009/10/more_about_wchar_t/
Carl Smotricz
I agree with this. See the comment about GLib's `g_utf8_strlen` under the question.
quark
A: 

EDIT: What locale are you using?

If you are going to iterating over a string, don't bother with getting its length with strlen. Just iterate until you see a NUL character:

char *p = str;
while(*p != '\0') {
    printf("%c\n", *p);
    ++p;
}

As for the umlauted characters and such, are they UTF-8? If the string is multi-byte, you could do something like this:

size_t n = strlen(str);
char *p = str;
char *e = p + n;
while(*p != '\0') {
    wchar_t wc;
    int l = mbtowc(&wc, p, e - p);
    if(l <= 0) break;
    p += l;
    /* do whatever with wc which is now in wchar_t form */
}

I honestly don't know if mbtowc will simply return -1 if it encounters a NUL in the middle of a MB character. If it does, you could just pass MB_CUR_MAX instead of e - p and do away with the strlen call. But I have a feeling this is not the case.

Evan Teran
I'm not sure... completely new to thinking about charsets. As somebody asked in the previous question, it looks like the input is UTF-8 but the codeset is ASCII...
pg-robban
Also, your code gives an error in the line p += mbtowc(Invalid operands to binary -
pg-robban
whoops, fixed that for ya. That's what I get for posting without compiling.
Evan Teran
Can you please explain this further? If I print to_morse(*p) it gives me lots of invalid morse codes.
pg-robban
well that code assumes that the string is multibyte (like utf-8). But also, look at the comment.. it says "do whatever with wc..." THAT is the multibyte character converted to a wchar_t.
Evan Teran
A: 

You could do something like

for (int i = 0; str[i]!='\0'; ++i){
    //do something with str[i]
}

Strings in C are terminated with '\0'. So it is possible to check for the end of the string like that.

Lucas
Simple enough, but doesn't work for the umlauted characters.
pg-robban
Here's what I did, and surprisingly works so far:` //loop until we get a NUL character for (int i = 0; str[i]!='\0'; ++i) { unsigned char letter = str[i]; //if we have an umlaut, read the next char instead if (0xC3 == letter) printf("%s ", to_morse(str[++i])); else printf("%s ", to_morse(str[i])); } ’Then I removed the check for umlaut characters in letter_Nr.
pg-robban
+1  A: 

On OS X, Cocoa is a solution - note the use of "%C" in NSLog - that's an unichar (16-bit Unicode character):

#import <Cocoa/Cocoa.h>

int main()
{
        NSAutoreleasePool * pool = [NSAutoreleasePool new];
        NSString * input = @"Hej du kalleåäö";

        printf("length of str: %d", [input length]);
        int i=0;
        for (i = 0; i < [input length]; i++)
        {
                NSLog(@"%C", [input characterAtIndex:i]);
        }

        [pool release];
}
diciu