如何在C ++(或C)中将所有重音字母更改为普通字母?
就此而言,我的意思是eéèêaàäâçc
会变成eeeeaaaacc
。
我尝试过手动解析字符串并逐个替换每一个字符串,但我认为必须有更好/更简单的方法,我不知道(这会保证我不会忘记任何重音信。)
我想知道标准库中是否已存在某个地图,或者是否所有重音字符都可以使用某些数学函数(例如floor(charCode-131/5) + 61)
)轻松映射到“普通”字母。
答案 0 :(得分:8)
char* removeAccented( char* str ) {
char *p = str;
while ( (*p)!=0 ) {
const char*
// "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"
tr = "AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiiOnooooo/0uuuuypy";
unsigned char ch = (*p);
if ( ch >=192 ) {
(*p) = tr[ ch-192 ];
}
++p; // http://stackoverflow.com/questions/14094621/
}
return str;
}
答案 1 :(得分:6)
我只在理论上知道。基本上,你执行Unicode规范化,然后进行一些分解,清除所有变音符号,然后重新组合。
答案 2 :(得分:6)
你首先应该用“重音字母”来定义你的意思,如果你所拥有的是一些扩展的8位ASCII,一个代码大于128的国家代码页,或者说一些utf8编码的字符串,那么必须做的事情大不相同。
但是你应该看看libicu,它提供了基于良好的基于unicode的重音字母操作所需的内容。
但它不会为你解决所有问题。例如,如果你收到一些中文或俄文字母,你该怎么办?如果你得到土耳其大写字母,我该怎么办?删除这个“我”的点?这样做会改变文本的含义......等等。这种问题对于unicode来说是无穷无尽的。即使是传统的排序顺序也取决于国家......
答案 3 :(得分:2)
假设值只是char
s,我会创建一个包含所需目标值的数组,然后用数组中相应的成员替换每个字符:
char replacement[256];
int n(0);
std::generate_n(replacement, 256, [=]() mutable -> unsigned char { return n++; });
replacement[static_cast<unsigned char>('é')] = 'e';
// ...
std::transform(s.begin(), s.end(), s.begin(),
[&](unsigned char c){ return replacement[c]; });
由于问题也用C标记:当使用C时,你需要创建合适的循环来执行相同的操作,但从概念上讲它也是一样的。同样地,如果你不能使用C ++ 2011,你只需使用合适的函数对象而不是lambda函数。
显然,replacement
数组只能设置一次并使用比上面概述的更智能的方法。但是,这个原则应该有效。如果你需要替换Unicode字符,事情会变得有趣一点:但是,对于一个,数组会相当大,此外该字符可能需要更改多个单词。
答案 4 :(得分:1)
使用ISO/IEC 8859-1(基于ASCII的标准字符编码)可以执行以下操作:
192 - 197
替换为A
224 - 229
替换为a
200 - 203
替换为E
232 - 235
替换为e
204 - 207
替换为I
236 - 239
替换为i
210 - 214
替换为O
242 - 246
替换为o
217 - 220
替换为U
249 - 252
替换为u
假设x是数字的代码,请对大写字母执行以下操作:
y = floor((x - 192) / 6)
y <= 2
,则z = ((y + 1) * 4) + 61
其他z = (y * 6) + 61
对小写字母执行以下操作:
y = floor((x - 224) / 6)
y <= 2
,则z = ((y + 1) * 4) + 93
其他z = (y * 6) + 93
最终答案z
是所需字母表的ASCII码
请注意,此方法仅在您使用ISO/IEC 8859-1时才有效。
答案 5 :(得分:1)
恐怕在这里没有简单的方法。
在应用程序中,我通过使用内部代码页表来解决这个问题,每个代码页表(如1250,1251,1252等)都包含实际的代码页字母和非变音符号等价物。表是使用c#自动生成的,它包含一些真正能够轻松实现的类(实际上有一些启发式),而且java允许快速地实现它。
这实际上是用于带有代码页的多字节数据,但它可以用于UNICODE字符串(只需搜索所有表中给定的unicode字母)。
答案 6 :(得分:0)
我的用例需要对一长串字符串进行不区分大小写的排序,其中一些字符串可能具有变音符号。因此,例如我希望“AñascoMunicipio”在“安克雷奇市政府”之前出现,而不是在“阿比维尔县”之前,因为它正在做一个天真的比较。
我的字符串以UTF-8编码,但它们可能包含一些扩展的ascii字符而不是正确的UTF-8 Unicode。我本可以将所有字符串提升为UTF-8,然后使用可以进行UTF-8字符串比较的库,但我希望完全控制速度和确定变量字符如何映射到非变量字符。 (我的选择包括将男性序数指标视为“o”,并将版权特征视为c。)
下面的“双字节”代码是UTF-8序列。 “单字节”代码扩展为ascii。
这是我获得代码的地方:
http://www.endmemo.com/unicode/unicodeconverter.php
void SimplifyStringForSorting( string *s, bool changeToLowerCase )
{
// C0 C1 C2 C3 C4 C5 E0 E1 E2 E3 E4 E5 AA // one-byte codes for "a"
// C3 80 C3 81 C3 82 C3 83 C3 84 C3 85 C3 A0 C3 A1 C3 A2 C3 A3 C3 A4 C3 A5 C2 AA // two-byte codes for "a"
// C8 C9 CA CB E8 E9 EA EB // one-byte codes for "e"
// C3 88 C3 89 C3 8A C3 8B C3 A8 C3 A9 C3 AA C3 AB // two-byte codes for "e"
// CC CD CE CF EC ED EE EF // one-byte codes for "i"
// C3 8C C3 8D C3 8E C3 8F C3 AC C3 AD C3 AE C3 AF // two-byte codes for "i"
// D2 D3 D4 D5 D6 F2 F3 F4 F5 F6 BA // one-byte codes for "o"
// C3 92 C3 93 C3 94 C3 95 C3 96 C3 B2 C3 B3 C3 B4 C3 B5 C3 B6 C2 BA // two-byte codes for "o"
// D9 DA DB DC F9 FA FB FC // one-byte codes for "u"
// C3 99 C3 9A C3 9B C3 9C C3 B9 C3 BA C3 BB C3 BC // two-byte codes for "u"
// A9 C7 E7 // one-byte codes for "c"
// C2 A9 C3 87 C3 A7 // two-byte codes for "c"
// D1 F1 // one-byte codes for "n"
// C3 91 C3 B1 // two-byte codes for "n"
// AE // one-byte codes for "r"
// C2 AE // two-byte codes for "r"
// DF // one-byte codes for "s"
// C3 9F // two-byte codes for "s"
// 8E 9E // one-byte codes for "z"
// C5 BD C5 BE // two-byte codes for "z"
// 9F DD FD FF // one-byte codes for "y"
// C5 B8 C3 9D C3 BD C3 BF // two-byte codes for "y"
int n = s->size();
int pos = 0;
for ( int i = 0 ; i < n ; i++, pos++ )
{
unsigned char c = (unsigned char)s->at( i );
if ( c >= 0x80 )
{
if ( i < ( n - 1 ) && (unsigned char)s->at( i + 1 ) >= 0x80 )
{
unsigned char c2 = SimplifyDoubleCharForSorting( c, (unsigned char)s->at( i + 1 ), changeToLowerCase );
if ( c2 < 0x80 )
{
s->at( pos ) = c2;
i++;
}
else
{
// s->at( pos ) = SimplifySingleCharForSorting( c, changeToLowerCase );
// if it's a double code we don't recognize, skip both characters;
// this does mean that we lose the chance to handle back-to-back extended ascii characters
// but we'll assume that is less likely than a unicode "combining character" or other
// unrecognized unicode character for data
i++;
}
}
else
{
unsigned char c2 = SimplifySingleCharForSorting( c, changeToLowerCase );
if ( c2 < 0x80 )
{
s->at( pos );
}
else
{
// skip unrecognized single-byte codes
pos--;
}
}
}
else
{
if ( changeToLowerCase && c >= 'A' && c <= 'Z' )
{
s->at( pos ) = c + ( 'a' - 'A' );
}
else
{
s->at( pos ) = c;
}
}
}
if ( pos < n )
{
s->resize( pos );
}
}
unsigned char SimplifyDoubleCharForSorting( unsigned char c1, unsigned char c2, bool changeToLowerCase )
{
// C3 80 C3 81 C3 82 C3 83 C3 84 C3 85 C3 A0 C3 A1 C3 A2 C3 A3 C3 A4 C3 A5 C2 AA // two-byte codes for "a"
// C3 88 C3 89 C3 8A C3 8B C3 A8 C3 A9 C3 AA C3 AB // two-byte codes for "e"
// C3 8C C3 8D C3 8E C3 8F C3 AC C3 AD C3 AE C3 AF // two-byte codes for "i"
// C3 92 C3 93 C3 94 C3 95 C3 96 C3 B2 C3 B3 C3 B4 C3 B5 C3 B6 C2 BA // two-byte codes for "o"
// C3 99 C3 9A C3 9B C3 9C C3 B9 C3 BA C3 BB C3 BC // two-byte codes for "u"
// C2 A9 C3 87 C3 A7 // two-byte codes for "c"
// C3 91 C3 B1 // two-byte codes for "n"
// C2 AE // two-byte codes for "r"
// C3 9F // two-byte codes for "s"
// C5 BD C5 BE // two-byte codes for "z"
// C5 B8 C3 9D C3 BD C3 BF // two-byte codes for "y"
if ( c1 == 0xC2 )
{
if ( c2 == 0xAA ) { return 'a'; }
if ( c2 == 0xBA ) { return 'o'; }
if ( c2 == 0xA9 ) { return 'c'; }
if ( c2 == 0xAE ) { return 'r'; }
}
if ( c1 == 0xC3 )
{
if ( c2 >= 0x80 && c2 <= 0x85 ) { return changeToLowerCase ? 'a' : 'A'; }
if ( c2 >= 0xA0 && c2 <= 0xA5 ) { return 'a'; }
if ( c2 >= 0x88 && c2 <= 0x8B ) { return changeToLowerCase ? 'e' : 'E'; }
if ( c2 >= 0xA8 && c2 <= 0xAB ) { return 'e'; }
if ( c2 >= 0x8C && c2 <= 0x8F ) { return changeToLowerCase ? 'i' : 'I'; }
if ( c2 >= 0xAC && c2 <= 0xAF ) { return 'i'; }
if ( c2 >= 0x92 && c2 <= 0x96 ) { return changeToLowerCase ? 'o' : 'O'; }
if ( c2 >= 0xB2 && c2 <= 0xB6 ) { return 'o'; }
if ( c2 >= 0x99 && c2 <= 0x9C ) { return changeToLowerCase ? 'u' : 'U'; }
if ( c2 >= 0xB9 && c2 <= 0xBC ) { return 'u'; }
if ( c2 == 0x87 ) { return changeToLowerCase ? 'c' : 'C'; }
if ( c2 == 0xA7 ) { return 'c'; }
if ( c2 == 0x91 ) { return changeToLowerCase ? 'n' : 'N'; }
if ( c2 == 0xB1 ) { return 'n'; }
if ( c2 == 0x9F ) { return 's'; }
if ( c2 == 0x9D ) { return changeToLowerCase ? 'y' : 'Y'; }
if ( c2 == 0xBD || c2 == 0xBF ) { return 'y'; }
}
if ( c1 == 0xC5 )
{
if ( c2 == 0xBD ) { return changeToLowerCase ? 'z' : 'Z'; }
if ( c2 == 0xBE ) { return 'z'; }
if ( c2 == 0xB8 ) { return changeToLowerCase ? 'y' : 'Y'; }
}
return c1;
}
unsigned char SimplifySingleCharForSorting( unsigned char c, bool changeToLowerCase )
{
// C0 C1 C2 C3 C4 C5 E0 E1 E2 E3 E4 E5 AA // one-byte codes for "a"
// C8 C9 CA CB E8 E9 EA EB // one-byte codes for "e"
// CC CD CE CF EC ED EE EF // one-byte codes for "i"
// D2 D3 D4 D5 D6 F2 F3 F4 F5 F6 BA // one-byte codes for "o"
// D9 DA DB DC F9 FA FB FC // one-byte codes for "u"
// A9 C7 E7 // one-byte codes for "c"
// D1 F1 // one-byte codes for "n"
// AE // one-byte codes for "r"
// DF // one-byte codes for "s"
// 8E 9E // one-byte codes for "z"
// 9F DD FD FF // one-byte codes for "y"
if ( ( c >= 0xC0 && c <= 0xC5 ) || ( c >= 0xE1 && c <= 0xE5 ) || c == 0xAA )
{
return ( ( c >= 0xC0 && c <= 0xC5 ) && !changeToLowerCase ) ? 'A' : 'a';
}
if ( ( c >= 0xC8 && c <= 0xCB ) || ( c >= 0xE8 && c <= 0xEB ) )
{
return ( c > 0xCB || changeToLowerCase ) ? 'e' : 'E';
}
if ( ( c >= 0xCC && c <= 0xCF ) || ( c >= 0xEC && c <= 0xEF ) )
{
return ( c > 0xCF || changeToLowerCase ) ? 'i' : 'I';
}
if ( ( c >= 0xD2 && c <= 0xD6 ) || ( c >= 0xF2 && c <= 0xF6 ) || c == 0xBA )
{
return ( ( c >= 0xD2 && c <= 0xD6 ) && !changeToLowerCase ) ? 'O' : 'o';
}
if ( ( c >= 0xD9 && c <= 0xDC ) || ( c >= 0xF9 && c <= 0xFC ) )
{
return ( c > 0xDC || changeToLowerCase ) ? 'u' : 'U';
}
if ( c == 0xA9 || c == 0xC7 || c == 0xE7 )
{
return ( c == 0xC7 && !changeToLowerCase ) ? 'C' : 'c';
}
if ( c == 0xD1 || c == 0xF1 )
{
return ( c == 0xD1 && !changeToLowerCase ) ? 'N' : 'n';
}
if ( c == 0xAE )
{
return 'r';
}
if ( c == 0xDF )
{
return 's';
}
if ( c == 0x8E || c == 0x9E )
{
return ( c == 0x8E && !changeToLowerCase ) ? 'Z' : 'z';
}
if ( c == 0x9F || c == 0xDD || c == 0xFD || c == 0xFF )
{
return ( ( c == 0x9F || c == 0xDD ) && !changeToLowerCase ) ? 'Y' : 'y';
}
return c;
}