0

Can anyone suggest a good method to convert a Japanese std::wstring to std::string?

I used the below code. Japanese strings are not converting properly on an English OS.

std::string WstringTostring(std::wstring str)
{
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "ja.JP.utf8");
    errno_t err = _wcstombs_s_l(&size, NULL, 0, &str[0], _TRUNCATE, lc);
    std::string ret = std::string(size, 0);
    err = _wcstombs_s_l(&size, &ret[0], size, &str[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size-1);
    return ret;
}

The wstring is "C\\files\\ブ種別.pdf".

The converted string is "C:\\files\\ブ種別.pdf".

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Saya
  • 9
  • 3
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/216112/discussion-on-question-by-saya-convert-japanese-wstring-to-stdstring). – Samuel Liew Jun 17 '20 at 02:40

2 Answers2

4

It actually looks right to me.

That is the UTF-8-encoded version of your input (which presumably was UTF-16 before conversion), but shown in its ASCII-decoded form due to a mistake somewhere in your toolchain.

You just need to calibrate your file/terminal/display to render text output as if it were UTF-8 (which it is).


Also, remember that std::string is just a container of bytes, and does not inherently specify or imply any particular encoding. So your question is rather "how can I convert UTF-16 (containing Japanese characters) into UTF-8 in Windows" or, as it turns out, "how do I configure my terminal to display UTF-8?".

If your display for this string is the Visual Studio locals window (which you suggest is the case with your comment "I observed the value of the "ret" string in local window while debugging") you are out of luck, because VS has no idea what encoding your string is in (nor does it attempt to find out).

For other aspects of Visual Studio, though, such as the console output window, there are various approaches to work around this (example).

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • You're assuming, wrongly, that the multibyte string is intended for display. – Seva Alekseyev Jun 16 '20 at 17:06
  • @SevaAlekseyev Only partially; I did add a "file" option too. The OP said that the strings don't escape their app. However, it is certainly true that they may be passing them to some library or API and, if that is so, I happily await that statement in a comment so that I can refine my answer to their situation. You don't know that it's a wrong assumption. Either way, they have a base answer, which is that _their string is already UTF-8 as desired_. – Asteroids With Wings Jun 16 '20 at 20:43
  • This whole thing is starting to look like an XY problem. – Seva Alekseyev Jun 17 '20 at 02:32
  • And I still think that UTF-8 is what the OP *wants*, but not what they *need* :) – Seva Alekseyev Jun 17 '20 at 02:36
  • I am getting file path from UI which is saved as String in c#.I need to pass the file path to cpp library which only accepts string. I have a wrapper . In this System.String needs to be convered to std::string.then the converted string will be passed to the cpp library – Saya Jun 17 '20 at 02:49
  • @Saya And is the C++ library printing the string? Where did you get your "broken" output from? And you're still repeatedly just saying "only accepts string" - what _encoding_ is it expecting? – Asteroids With Wings Jun 17 '20 at 10:32
  • I am not printing . I need to do some process with the file. its a legacy dll .After the wcstomb convertion, I observed the value of the "ret" string in local window while debugging – Saya Jun 17 '20 at 10:49
  • unable to do this, Instead of string i am trying to pass the wstring itself. – Saya Jun 17 '20 at 10:54
  • I have another method.In this, I have to pass the japanese file path as const char*. I tried to convert from wstring but i am getting junk characters only – Saya Jun 17 '20 at 10:56
  • need to convert to utf8 encoding – Saya Jun 17 '20 at 10:59
  • @Saya: Right, so, again, **you have done that successfully**, and the only issue is how you're _observing_ the result. I don't know how many other ways to say that, frankly. – Asteroids With Wings Jun 17 '20 at 11:10
  • @Saya: _"I observed the value of the "ret" string in local window while debugging"_ Yep, so, that's because the locals window doesn't know or care what the encoding is. _It doesn't know your string is UTF-8_. The locals window is just limited in that way. There is no problem here. Your string is fine. Pass it to the library, open your file, and away you go. – Asteroids With Wings Jun 17 '20 at 11:11
  • @AsteroidsWithWings no, the junk characters only passing to the method. it couldn't find the correct the file due to this junk characters. – Saya Jun 17 '20 at 11:15
  • In the new try also I am having problem. I need to convert the japanese filepath wchar_t to const char*. I am getting the same junk chracters. – Saya Jun 17 '20 at 11:17
  • @Saya They're not junk characters. They are the bytes that make up the correct UTF-8 representation of your string. **The conversion was successful.** If the library couldn't find the file, then either your use of the library is incorrect, or the file doesn't exist where you say it does. – Asteroids With Wings Jun 17 '20 at 13:30
0

EDIT: some things first. Windows has the notion of the ANSI codepage. It's the default codepage of non-Unicode strings that Windows assumes. Every program that uses non-Unicode versions of Windows API, and doesn't specify the codepage explicitly, uses the ANSI codepage.

The ANSI codepage is driven by the "System default locale" setting in Control Panel. As of Windows 10 May 2020, it's under Region/Administrative/Change system locale. It takes admin rights to change that setting.

By default, Windows with the system default locale set to English uses codepage 1252 as the ANSI codepage. That codepage doesn't contain the Japanese characters. So using Japanese in Unicode unaware programs in that situation is hard or impossible.

It looks like the OP wants or has to use a piece of third part C++ code that uses multibyte strings (std::string and/or char*). That doesn't necessarily mean that it's Unicode unaware, but it might. What the OP is trying to do entirely depends on the way that third party library is coded. It might not be possible at all.


Looks like your problem is that some piece of third party code expects a file name in ANSI, and uses ANSI functions to open that file. In an English system with the default value of the system locale, Japanese can't be converted to ANSI, because the ANSI codepage (CP1252 in practice) doesn't contain the Japanese characters.

What I think you should do, you should get a short file name instead using GetShortPathNameW, convert that file path to ANSI, and pass that string. Like this:

std::string WstringFilenameTostring(std::wstring str)
{
    wchar_t ShortPath[MAX_PATH+1];
    DWORD dw = GetShortPathNameW(str.c_str(), ShortPath, _countof(ShortPath));

    char AnsiPath[MAX_PATH+1];
    int n = WideCharToMultiByte(CP_ACP, 0, ShortPath, -1, AnsiPath, _countof(AnsiPath), 0, 0);
    return string(AnsiPath);
}

This code is for filenames only. For any other Japanese string, it will return nonsense. In my test, it converted "日本語.txt" to something unreadable but alphanumeric :)

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • I wouldn't rely on this - users can disable short path names, see: https://support.microsoft.com/en-gb/help/121007/how-to-disable-8-3-file-name-creation-on-ntfs-partitions – Paul Sanders Jun 16 '20 at 17:09
  • @PaulSanders Unable to do this. Access denied for me – Saya Jun 16 '20 at 17:25
  • @Saya You need to do this from an elevated command prompt (i.e. one with Administrator privileges), as the article explains. – Paul Sanders Jun 16 '20 at 17:27
  • I am trying this in office pc. they restrict access. – Saya Jun 16 '20 at 17:29
  • @Seva Thank you for your code. But I need to convert japanese string. anyway thanks – Saya Jun 16 '20 at 17:32
  • For Japanese strings that are intended for other purposes (e. g. display or writing *into* files), you'd have to use different logic. Looks like you are working with a third party library; **what is it**? Maybe it has a Unicode compliant version. – Seva Alekseyev Jun 16 '20 at 17:34
  • I tried marshal_cppstd.h from Microsoft. For this also I got junk characters – Saya Jun 16 '20 at 17:38
  • The combination of non-Japanese locale and non-Unicode software **will always be complicated**. *Did I solve the filename problem?* If so, please accept an answer and let's move on to your next problem. **There is no way to convert Japanese text into CP1252**. That's a fact of life, there's nothing you can do about that. All you can have is various workarounds. – Seva Alekseyev Jun 16 '20 at 17:41
  • . _wcstombs_l and _wcstombs_s_l only available – Saya Jun 16 '20 at 17:53
  • Use `_get_current_locale()` to get the system default locale. Don't free it. Also, see the my edit. Please, what is the library that requires `string`? – Seva Alekseyev Jun 16 '20 at 17:55
  • _get_current_locale() is not supported for me . use std::string or include stdio.h – Saya Jun 16 '20 at 18:06
  • Okay, see the edit. Looks like you can use Windows functions, so here's a fragment with WideCharToMultiByte instead. – Seva Alekseyev Jun 16 '20 at 18:11
  • int n = WideCharToMultiByte(CP_ACP, 0, ws, -1, AnsiPath, _countof(AnsiPath), 0, 0); in this ws was not used in your code. are you trying to use DWORD dw. But we con't use dw in WIdeCharToMultiByte – Saya Jun 17 '20 at 02:42
  • Sorry, `ws` came from a copy-paste. I meant `ShortPath`, which is the widestring version of the short file name. No need to use `dw`, because `ShortPath` is null terminated, and you can pass -1 for the 4th argument. Edited the answer. – Seva Alekseyev Jun 17 '20 at 13:01