Visual Studio 2019 C++ 项目中的特殊字符并用它们执行 CMD 命令

2023-12-05

首先,我只想在控制台中使用波罗的海字符并用它们执行 CMD 命令,但问题是从默认/标准控制台 C++ 应用程序开始的。

#include <iostream>
int main() {
    string output = "āāāčččēēēē";

    cout << output << endl;
}

早些时候,我在堆栈上提出了这个问题 -如何在 DEFAULT C++ 项目中或在 Visual Studio 2019 中使用 C++ 的 mysql 连接器时使用 UTF8 字符(Latin7_general_ci 到 UTF-8)?

我在测试中发现:如果我将 UTF8 字符串转换为 Latin1 字符串,然后 cout 或打印十六进制值,我会在控制台中输出一些特殊字符。例如 -

**char s2[256] = "\xc3\xa9";**  printed is outputted as "ķ" THAT MEANS I need to convert strings into correct HEX values when it is needed, and some people might know how it might be one.

但我的代码逻辑需要一个功能来使用此字符串在 CMD 中使用 cp。因此,稍后转换为字符串,我的 CMD 无法工作,尽管 cp 命令 CMD 必须执行的输出似乎在控制台中正确显示。

// Example program
#include <iostream>
#include <string>
#include <fstream>
#include <sstream> 
#include <stdexcept>
#include <stdlib.h> 
#include <stdio.h> 
#include <time.h> 
#include <cstring> 
#include <cstdint>
#include <locale> 
#include <cstdlib>





int GetUtf8CharacterLength(unsigned char utf8Char)
{
    if (utf8Char < 0x80) return 1;
    else if ((utf8Char & 0x20) == 0) return 2;
    else if ((utf8Char & 0x10) == 0) return 3;
    else if ((utf8Char & 0x08) == 0) return 4;
    else if ((utf8Char & 0x04) == 0) return 5;

    return 6;
}

char Utf8ToLatin1Character(char* s, int* readIndex)
{
    int len = GetUtf8CharacterLength(static_cast<unsigned char>(s[*readIndex]));
    if (len == 1)
    {
        char c = s[*readIndex];
        (*readIndex)++;

        return c;
    }

    unsigned int v = (s[*readIndex] & (0xff >> (len + 1))) << ((len - 1) * 6);
    (*readIndex)++;
    for (len--; len > 0; len--)
    {
        v |= (static_cast<unsigned char>(s[*readIndex]) - 0x80) << ((len - 1) * 6);
        (*readIndex)++;
    }

    return (v > 0xff) ? 0 : (char)v;
}

// overwrites s in place
char* Utf8ToLatin1String(char* s)
{
    for (int readIndex = 0, writeIndex = 0; ; writeIndex++)
    {
        if (s[readIndex] == 0)
        {
            s[writeIndex] = 0;
            break;
        }

        char c = Utf8ToLatin1Character(s, &readIndex);
        if (c == 0)
        {
            c = '_';
        }

        s[writeIndex] = c;
    }

    return s;
}


int main()
{
    char s2[256] = "\xc3\xa9";
    Utf8ToLatin1String(s2);

    std::cout << s2 << std::endl;

    std::string locations2 = ("C:\\Users\\Janis\\Desktop\\TEST2\\");
    std::string txtt = (".txt");
    std::string copy2 = ("copy /-y ");

    std::string space = " ";
    std::string PACIENTI2 = "C:\\PACIENTI\\";




    std::string element = copy2 + locations2 + s2 + txtt;

    std::string cmd = element + space + PACIENTI2 + s2 + txtt;

    std::cout << cmd << std::endl;

    FILE* pipe = _popen(cmd.c_str(), "r");
}

所以我们需要真正解决两个问题,从已经给定的十六进制字符串创建,并确保它在 CMD 中工作。


我在你的另一个问题中已经给你提供了很好的答案。这是类似的东西。

你的程序可以使用UTF-8编码和控制台可以使用不同的编码,但是您必须向标准库提供如何对每个数据源进行编码的提示。
当然,如果目标编码没有涵盖不支持特定字符,则必须启动一些后备(请参见底部的示例)。

必须明确定义编码才能使一切正常工作的 4 个领域:

  • 你的源代码。 VS 使用系统区域设置来使用编码,这很糟糕。强制 VS 和所有编辑器使用通用编码,UTF-8 选择是最好的。最好告知编译器源代码是如何编码的:cl /source-charset:utf-8 .....
  • 你的可执行文件。您必须定义在最终可执行文件中应编码哪种编码字符串文字。这里UTF-8也是最好的:cl .... /execution-charset:utf-8 .....
  • 当您运行应用程序时,您必须告知标准库您的字符串文字定义的编码类型或程序逻辑中使用的编码类型。因此,在执行开始时,代码中的某个位置需要这样的内容:
std::locale::global(std::locale{".utf-8"});
  • 最后你必须指示流应该使用哪种编码。因此对于std::cout and std::cin您应该设置系统默认的区域设置:
    auto streamLocale = std::locale{""}; 
    // this impacts date/time/floating point formats, so you may want tweak it just to use sepecyfic encoding and use C-loclae for formating
    std::cout.imbue(streamLocale);
    std::cin.imbue(streamLocale);

之后,一切都应该按预期工作,无需显式进行转换的代码。
由于有 4 个地方会出错,这就是人们遇到麻烦的原因,并且互联网上充满了“黑客”解决方案。

这是一些测试程序来证明我的观点:

#include <iostream>
#include <locale>
#include <exception>
#include <string>

void setupLocale(int argc, const char *argv[])
{
    std::locale def{""};
    std::locale::global(argc > 1 ? std::locale{argv[1]} : def);
    auto streamLocale = argc > 2 ? std::locale{argv[2]} : def;
    std::cout.imbue(streamLocale);
    std::cin.imbue(streamLocale);
}

void printSeparator()
{
    std::cout << "---------\n";
}

void printTestStuff()
{
    std::cout << "Wester Europe: āāāčččēēēēßÞÖöñÅÃ\n";
    std::cout << "Central Europe: ąĄÓóŁłĘężćźŰűÝýĂă\n";
    std::cout << "China: 字集碼是把字符集中的字符编码为指定集合中某一对象\n";
    std::cout << "Korean: 줄여서 인코딩은 사용자가 입력한\n";
}

int main(int argc, const char *argv[]) {
    try{
        setupLocale(argc, argv);
        printSeparator();
        printTestStuff();
        printSeparator();
    }
    catch(const std::exception& e)
    {
        std::cerr << e.what() << '\n';
    }
}

以及它是如何构建和运行以显示其工作原理的(请注意,这也涵盖了使用无效编码的情况):

C:\Users\User\Downloads>cl /source-charset:utf-8 /execution-charset:utf-8 /EHsc encodings.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29336 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

encodings.cpp
Microsoft (R) Incremental Linker Version 14.28.29336.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:encodings.exe
encodings.obj

C:\Users\User\Downloads>chcp
Active code page: 437

C:\Users\User\Downloads>encodings.exe
---------
Wester Europe: Ä?Ä?Ä?Ä?Ä?Ä?Ä"Ä"Ä"Ä"AYAzA-AA±A.Aƒ
Central Europe: Ä.Ä,A"A3Å?Å,Ä~ÄTżÄ╪źŰűA?A½Ä,ă
China: å--é>+碼æ~_æSSå--ç¬▌é>+ä,-çs,å--ç¬▌ç¼-ç ?ä,ºæO╪årsé>+å?^ä,-æY?ä,?å_1象
Korean: ì,ì-¬ì,o ì?,ì½"ë"cì?? ì,¬ìscìz?ê°? ìz.ë ¥ío
---------

C:\Users\User\Downloads>encodings.exe .65001
---------
Wester Europe: aaaccceeeeß_ÖöñÅA
Central Europe: aAOóLlEezczUuYyAa
China: ????????????????????????
Korean: ??? ???? ???? ???
---------

C:\Users\User\Downloads>encodings.exe .65001 .437
---------
Wester Europe: aaaccceeeeß_ÖöñÅA
Central Europe: aAOóLlEezczUuYyAa
China: ????????????????????????
Korean: ??? ???? ???? ???
---------

C:\Users\User\Downloads>encodings.exe .65001 .1250
---------
Wester Europe: aaaccceeeeß_ÖöñÅA
Central Europe: aAOóLlEezczUuYyAa
China: ????????????????????????
Korean: ??? ???? ???? ???
---------

C:\Users\User\Downloads>chcp 1250
Active code page: 1250

C:\Users\User\Downloads>encodings.exe .65001 .1250
---------
Wester Europe: aaačččeeeeß?ÖönAA
Central Europe: ąĄÓóŁłĘężćźŰűÝýĂă
China: ????????????????????????
Korean: ??? ???? ???? ???
---------

C:\Users\User\Downloads>chcp 65001
Active code page: 65001

C:\Users\User\Downloads>encodings.exe
---------
Wester Europe: ÄÄÄÄÄÄēēēēßÞÖöñÅÃ
Central Europe: ąĄÓóÅłĘężćźŰűÃýĂă
China: 字集碼是把字符集中的字符编ç ä¸ºæŒ‡å®šé›†åˆä¸­æŸä¸€å¯¹è±¡
Korean: 줄여서 ì¸ì½”ë”©ì€ ì‚¬ìš©ìžê°€ 입력한
---------

C:\Users\User\Downloads>encodings.exe .65001
---------
Wester Europe: āāāčččēēēēßÞÖöñÅÃ
Central Europe: ąĄÓóŁłĘężćźŰűÝýĂă
China: 字集碼是把字符集中的字符编码为指定集合中某一对象
Korean: 줄여서 인코딩은 사용자가 입력한
---------

C:\Users\User\Downloads>encodings.exe .65001 .65001
---------
Wester Europe: āāāčččēēēēßÞÖöñÅÃ
Central Europe: ąĄÓóŁłĘężćźŰűÝýĂă
China: 字集碼是把字符集中的字符编码为指定集合中某一对象
Korean: 줄여서 인코딩은 사용자가 입력한
---------

C:\Users\User\Downloads>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Visual Studio 2019 C++ 项目中的特殊字符并用它们执行 CMD 命令 的相关文章

随机推荐