-1

I have the following code:

#include <iostream>
#include <cstdlib>

int main(){
  string letra = "méxico";

  for(int i=0;i<letra.size();i++){
    cout << letra[i] << endl;
  }

  return 0;
}

What I get as a result:

m
�
�
x
i
c
o

Why are 7 characters instead of 6?, If I do this:

cout << letra << endl;

I get:

méxico

What's going on? I've tried using

setlocale(LC_ALL,es_MX.UTF-8);
setlocale(LC_ALL,"");

And although the function does not return "NULL", it does not work. I use Codeblocks 16.01, gcc 4.9, g++ 4.9 on Linux.

Javier Ramírez
  • 1,001
  • 2
  • 12
  • 23
  • 3
    You have a typo, `i==0` should be `i=0`. Also you should use [`wstring` instead of `string`](https://stackoverflow.com/questions/402283/stdwstring-vs-stdstring) along with [`wcout` instead of `cout`](https://stackoverflow.com/questions/8788057/how-to-initialize-and-print-a-stdwstring) – Cory Kramer May 01 '17 at 19:17
  • 1
    Required Reading for unicode: https://en.wikipedia.org/wiki/Precomposed_character – Mooing Duck May 01 '17 at 19:18
  • 1
    @CoryKramer That depends. Actually, the top answer to the Q you linked advices *against* using `wstring` on Linux. The important point is that some characters can take up more than one `char` in an `std::string`. Printing the complete string should work fine on Linux. – Baum mit Augen May 01 '17 at 19:21
  • @Javier Ramírez: It works fin with gcc on Windows using `setlocale(LC_ALL, "");` also note you are using `==` instead of `=` inside the `for` loop. – Shadi May 01 '17 at 19:31
  • @JavierRamirez -- I suggest *not* to put quoted string in your source code that are not ASCII characters. The reason is that you don't know what the source editor will do with those characters (the accented `e`) when the file is saved. You need to be darn sure what the editor will translate those characters to when the source file is saved. If the file saves that string as something you didn't expect, all of the locale functions in the world are not going to help you, since it will be too late. – PaulMcKenzie May 01 '17 at 19:41
  • I had already seen this stackoverflow.com/questions/31357380/c-non-ascii-letters. And no, it does not work. Please, before placing "duplicate" first make sure you know if that worked for me. – Javier Ramírez May 01 '17 at 19:54
  • @JavierRamírez -- You don't know or have not told us exactly what the final string in the executable really is. Like I said, you cannot guarantee a quoted string in your source code that uses non-ASCII characters will work as you expect. Show us the actual string of bytes in your program that represents that string -- if the `e` has been mangled in any way, well, you were warned. – PaulMcKenzie May 01 '17 at 19:58

1 Answers1

0

std::string doesn't recognize encodings; its operator[] returns its individual bytes, not individual characters.

On Unicode, é is actually composed of two bytes, and with letra[i] you get each one of those individually. However, operator<< for std::strings does the right job by "composing" those two bytes and actually printing the character é.

To access each character individually (not random access however), you can use mbtowc defined in <cstdlib>:

int mbtowc(wchar_t* pwc, const char* s, size_t n);

It examines at most n bytes of s to find a character and place it at pwc, returning the number of bytes read. Your printing routine becomes something like this:

mbtowc(nullptr, 0, 0);
for (int i = 0; i < letra.size();)
{
    wchar_t wc;
    int r = mbtowc(&wc, &letra[i], letra.size()-i);
    cout << wc << endl;
    if (r <= 0) break;
    i += r;
}
JoaoBapt
  • 195
  • 1
  • 11