string s="x1→(y1⊕y2)∧z3";
for(auto i=s.begin(); i!=s.end();i++){
if(*i=='→'){
...
}
}
比较字符的方法肯定是错误的,正确的做法是什么?我正在使用vs2013。
首先,您需要一些基本了解程序如何处理Unicode的知识。否则,您应该阅读一下,我很喜欢Joel on Software上的这篇文章。
实际上,您有两个问题:
问题#1:将字符串放入程序中
您的第一个问题是将实际字符串放入string s
中。根据源代码文件的编码方式,MSVC可能会破坏该字符串中的任何非ASCII字符。
要么将C++文件保存为UTF-16(Windows混淆地称为 Unicode ),并使用whcar_t
和wstring
(有效地将表达式编码为UTF-16)。保存为带BOM的UTF-8也可以。任何其他编码,您的L"..."
字符文字将包含错误的字符。
请注意,其他平台可能将wchar_t
定义为4个字节而不是2个字节。因此,处理U + FFFF以上的字符将是不可移植的。
在所有其他情况下,您不能只是在源文件中写入那些字符。最具可移植性的方法是将字符串文字编码为UTF-8,对于所有非ASCII字符,使用\ x 转义代码。就像这样:
"x1 \ xe2 \ x86 \ x92a \ xe2 \ x8a \ x95"“b)”
而不是"x1→(a⊕b)"
。
是的,那就是最难以阅读和繁琐的。根本问题是MSVC实际上并不支持使用UTF-8。您可以通过这里的问题概述: 如何在Visual C ++ 2008中创建UTF-8字符串文字。
但是,请考虑这些字符串在源代码中实际显示的频率。
问题#2:查找字符
(如果您正在使用UTF-16,则可以找到L'→'
字符,因为该字符可以表示为一个whcar_t
。对于U + FFFF以上的字符,您必须使用下面的宽版本解决方法。)
无法定义代表箭头字符的char
。但是,您可以使用字符串:"\xe2\x86\x92"
。(那是一个带有3个箭头字符和\0
终止符的字符串。
现在,您可以在表达式中搜索此字符串:
s.find("\xe2\x86\x92");
UTF-8编码方案保证了总是能找到正确的字符,但请记住这是一个字节偏移量。
wchar_t
不能编码任何Unicode字符。 - roelandL"a→b"
,您可能会惊讶于实际上会出现在您的字符串中的内容。 - roelandL"aâ\u0086\u0092b"
。 - roeland我的评论太长了,所以我把它提交为一个答案。
问题在于每个人都集中于Unicode可能使用的不同编码(UTF-8、UTF-16、UCS2等)的问题。但你在这里的问题将刚刚开始。
还有一个复合字符的问题,这将真正混乱你尝试进行的任何搜索。
假设你正在寻找字符'é',你在Unicode中找到它为U+00E9并进行搜索,但不能保证这是表示此字符的唯一方法。该文档还可能包含U+0065 U+0301组合。它实际上是完全相同的字符。
是的,不仅是“看起来一样”的字符,而且确实是相同的字符,因此任何软件甚至一些编程库都会自由地转换一个字符到另一个字符,甚至不告诉你。
因此,如果你希望进行强大的搜索,你需要表示不仅Unicode的不同编码,而且字符本身,包括复合字符和已经准备好的字符之间的相等性。
wchar_t
对于 Unicode 字符 U+FFFF 以上的字符也会有同样的问题。 - roeland