簡體   English   中英

setw() 在包含 UTF-8 多字節字符/代碼點的字符串上注入錯誤輸出

[英]setw() imbues wrong output on strings containing UTF-8 multi-byte characters/code points

我需要輸出一些可能是 UTF-8 多字節的數據,我需要使用setw()保持它們的格式。

當字符是多字節序列時,對齊丟失並且setw()無法正常工作。

//#include <stdio.h>
#include <locale>
#include <iostream>
//#include <fstream>
#include <iomanip>
//#include <sstream>

int main(int argc, char **argv)
{ 
    std::locale l=std::locale("en_US.utf8");
    std::locale::global(l); 
    std::cout.imbue(l);
    std::cout<<std::endl;
    std::cout<<std::setw(40)<<std::right<<"hi “my” friend"<<std::endl;
    std::cout<<std::setw(40)<<std::right<<"hi -my- friend"<<std::endl;
    return 0;
}

輸出是:

                  hi “my” friend
                      hi -my- friend

我錯過了什么?

我必須指出,字符不是正常的" ,而是另外兩個字符,在 UTF-8 中每個字符由三個字節表示。

字符串文字"hi -my- friend"包含 14 個字符。 字符串文字"hi “my” friend"包含 18 個字符:符號由 3 個字符/字節編碼 cout按原樣輸出這些字符,目標終端將 3 字節序列轉換為單個符號。

因此,從流的角度來看,一切都很好:它輸出(width - strlen(literal) )填充字符,然后是strlen(literal)字符, width總計。 它不處理可能的多字節序列,也不知道目標終端將幾個字符轉換為一個符號。

您可以通過計算字符串在寬表示中的字符數來完成此格式設置,然后計算字符串長度和寬表示之間的差異,然后將該差異添加到傳遞給setw ,例如:

std::mbstate_t state = std::mbstate_t();
std::string s = "hi “my” friend";
const char *cp = s.c_str();
size_t len = mbsrtowcs(nullptr, &cp, s.size(), &state);
std::cout << setw(40 + (s.size() - len)) << std::right << s << std::endl;

您可以將此功能編碼為一個函數,該函數將字符串作為參數並返回要添加到 setw 調用的差值:

size_t f(const std::string &s)
{
  std::mbstate_t state = std::mbstate_t();
  const char *cp = s.c_str();
  size_t len = mbsrtowcs(nullptr, &cp, s.size(), &state);
  return s.size() - len;
}
...

std::string s = "hi “my” friend";
std::cout << std::setw(40 + f(s)) << std::right << s << std::endl;


暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM