gpt4 book ai didi

c++ - 非 ascii 字符的字典顺序排序

转载 作者:行者123 更新时间:2023-11-28 01:15:24 27 4
gpt4 key购买 nike

我已经通过以下代码对ascii字符进行了字典排序:

std::ifstream infile;
std::string line, new_line;
std::vector<std::string> v;
while(std::getline(infile, line))
{
// If line is empty, ignore it
if(line.empty())
continue;
new_line = line + "\n";
// Line contains string of length > 0 then save it in vector
if(new_line.size() > 0)
v.push_back(new_line);
}
sort(v.begin(), v.end());

结果应该是:A啊啊阿比尤特bb贝赫尔cgh剪刀....

但我不知道如何按如下顺序对 ascii 和非 ascii 字符进行词典排序:a A À Á Ã brg Baq ckrwg CkfgF d Dgrn...请告诉我如何编写代码它。谢谢!

最佳答案

OP 没有,但我觉得值得一提:谈到非 ASCII 字符,还应考虑编码。

The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

像 À、Á 和 Â 这样的字符不是 7 bit ASCII 的一部分但被考虑在各种 8 位编码中,例如Windows 1252 .因此,不允许某个字符(不是 ASCII 的一部分)在任何编码中具有相同的代码点(即数字)。 (大多数字符在大多数编码中都没有数字。)

然而,Unicode 提供了一个独特的编码表包含任何其他编码的所有字符(我相信)。有如下实现

  • UTF-8其中代码点由 1 个或多个 8 位值表示(使用 char 存储)
  • UTF-16其中代码点用 1 或 2 个 16 位值表示(用 std::char16_t 或可能用 wchar_t 存储)
  • UTF-32其中代码点用 1 个 32 位值表示(用 std::char32_t 存储,或者如果有足够的大小,可能用 wchar_t 存储)。

关于wchar_t的大小: Character types .

话虽如此,我使用了 wchar_tstd::wstring在我的示例中,使变音符号的使用独立于语言环境和平台。


std::sort() 中使用的顺序对 T 的范围进行排序元素默认定义为
bool < operator(const T&, const T&) < T 的运算符.
不过有std::sort()的味道改为定义自定义谓词。

自定义谓词必须匹配签名并且必须提供 strict weak ordering relation .

因此,我建议使用 std::map它将字符映射到一个索引,从而产生预期的顺序。

这是我在示例中使用的谓词:

  // sort words
auto charIndex = [&mapChars](wchar_t chr)
{
const CharMap::const_iterator iter = mapChars.find(chr);
return iter != mapChars.end()
? iter->second
: (CharMap::mapped_type)mapChars.size();
};

auto pred
= [&mapChars, &charIndex](const std::wstring &word1, const std::wstring &word2)
{
const size_t len = std::min(word1.size(), word2.size());
// + 1 to include zero terminator
for (size_t i = 0; i < len; ++i) {
const wchar_t chr1 = word1[i], chr2 = word2[i];
const unsigned i1 = charIndex(chr1), i2 = charIndex(chr2);
if (i1 != i2) return i1 < i2;
}
return word1.size() < word2.size();
};

std::sort(words.begin(), words.end(), pred);

从下到上:

  1. std::sort(words.begin(), words.end(), pred);使用提供谓词 pred 的第三个参数调用为我的定制订单。
  2. λ pred() , 比较两个 std::wstring逐个字符。因此,比较是使用 std::map 完成的。 mapChars哪些 map wchar_tunsigned即在我的订单中排名靠前的角色。
  3. mapChars仅存储所有字符值的一部分。因此,可能无法在 mapChars 中找到任务中的角色。 .为了处理这个,一个辅助 lambda charIndex()使用返回 mapChars.size()在这种情况下——它被授予高于所有出现的指数。

类型CharMap只是一个typedef :

typedef std::map<wchar_t, unsigned> CharMap;

初始化一个CharMap ,使用了一个函数:

CharMap makeCharMap(const wchar_t *table[], size_t size)
{
CharMap mapChars;
unsigned rank = 0;
for (const wchar_t **chars = table; chars != table + size; ++chars) {
for (const wchar_t *chr = *chars; *chr; ++chr) mapChars[*chr] = rank;
++rank;
}
return mapChars;
}

必须使用一个字符串数组来调用它,该数组包含按预期顺序排列的所有字符组:

const wchar_t *table[] = {
L"aA", L"äÄ", L"bB", L"cC", L"dD", L"eE", L"fF", L"gG", L"hH", L"iI", L"jJ", L"kK", L"lL", L"mM", L"nN",
L"oO", L"öÖ", L"pP", L"qQ", L"rR", L"sS", L"tT", L"uU", L"üÜ", L"vV", L"wW", L"xX", L"yY", L"zZ"
};

完整示例:

#include <string>
#include <sstream>
#include <vector>

static const wchar_t *table[] = {
L"aA", L"äÄ", L"bB", L"cC", L"dD", L"eE", L"fF", L"gG", L"hH", L"iI", L"jJ", L"kK", L"lL", L"mM", L"nN",
L"oO", L"öÖ", L"pP", L"qQ", L"rR", L"sS", L"tT", L"uU", L"üÜ", L"vV", L"wW", L"xX", L"yY", L"zZ"
};

static const wchar_t *tableGerman[] = {
L"aAäÄ", L"bB", L"cC", L"dD", L"eE", L"fF", L"gG", L"hH", L"iI", L"jJ", L"kK", L"lL", L"mM", L"nN",
L"oOöÖ", L"pP", L"qQ", L"rR", L"sS", L"tT", L"uUüÜ", L"vV", L"wW", L"xX", L"yY", L"zZ"
};

typedef std::map<wchar_t, unsigned> CharMap;

// fill a look-up table to map characters to the corresponding rank
CharMap makeCharMap(const wchar_t *table[], size_t size)
{
CharMap mapChars;
unsigned rank = 0;
for (const wchar_t **chars = table; chars != table + size; ++chars) {
for (const wchar_t *chr = *chars; *chr; ++chr) mapChars[*chr] = rank;
++rank;
}
return mapChars;
}

// conversion to UTF-8 found in https://stackoverflow.com/a/7561991/7478597
// needed to print to console
// Please, note: std::codecvt_utf8() is deprecated in C++17. :-(
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;

// collect words and sort accoring to table
void printWordsSorted(
const std::wstring &text, const wchar_t *table[], const size_t size)
{
// make look-up table
const CharMap mapChars = makeCharMap(table, size);
// strip punctuation and other noise
std::wstring textClean;
for (const wchar_t chr : text) {
if (chr == ' ' || mapChars.find(chr) != mapChars.end()) {
textClean += chr;
}
}
// fill word list with sample text
std::vector<std::wstring> words;
for (std::wistringstream in(textClean);;) {
std::wstring word;
if (!(in >> word)) break; // bail out
// store word
words.push_back(word);
}
// sort words
auto charIndex = [&mapChars](wchar_t chr)
{
const CharMap::const_iterator iter = mapChars.find(chr);
return iter != mapChars.end()
? iter->second
: (CharMap::mapped_type)mapChars.size();
};
auto pred
= [&mapChars, &charIndex](const std::wstring &word1, const std::wstring &word2)
{
const size_t len = std::min(word1.size(), word2.size());
// + 1 to include zero terminator
for (size_t i = 0; i < len; ++i) {
const wchar_t chr1 = word1[i], chr2 = word2[i];
const unsigned i1 = charIndex(chr1), i2 = charIndex(chr2);
if (i1 != i2) return i1 < i2;
}
return word1.size() < word2.size();
};
std::sort(words.begin(), words.end(), pred);
// remove duplicates
std::vector<std::wstring>::iterator last = std::unique(words.begin(), words.end());
words.erase(last, words.end());
// print result
for (const std::wstring &word : words) {
std::cout << utf8_conv.to_bytes(word) << '\n';
}
}

template<typename T, size_t N>
size_t size(const T (&arr)[N]) { return sizeof arr / sizeof *arr; }

int main()
{
// a sample string
std::wstring sampleText
= L"In the German language the ä (a umlaut), ö (o umlaut) and ü (u umlaut)"
L" have the same lexicographical rank as their counterparts a, o, and u.\n";
std::cout << "Sample text:\n"
<< utf8_conv.to_bytes(sampleText) << '\n';
// sort like requested by OP
std::cout << "Words of text sorted as requested by OP:\n";
printWordsSorted(sampleText, table, size(table));
// sort like correct in German
std::cout << "Words of text sorted as usual in German language:\n";
printWordsSorted(sampleText, tableGerman, size(tableGerman));
}

输出:

Words of text sorted as requested by OP:
a
and
as
ä
counterparts
German
have
In
language
lexicographical
o
ö
rank
same
the
their
u
umlaut
ü
Words of text sorted as usual in German language:
ä
a
and
as
counterparts
German
have
In
language
lexicographical
o
ö
rank
same
the
their
u
ü
umlaut

Live Demo on coliru

注意:

我的初衷是用std::wcout做输出.这对 ä、ö、ü 不能正常工作。因此,我查找了 simple way to convert wstring s to UTF-8 .我已经知道 coliru 支持 UTF-8。


@Phil1970提醒我,我忘了提其他事情:

字符串的排序(根据“人类字典”顺序)通常由 std::locale 提供。 . std::collate 提供依赖于语言环境的字符串字典顺序。

语言环境很重要,因为字符的顺序可能会因不同的语言环境而异。 std::collate 医生。有一个很好的例子:

Default locale collation order: Zebra ar förnamn zebra ängel år ögrupp
English locale collation order: ängel ar år förnamn ögrupp zebra Zebra
Swedish locale collation order: ar förnamn zebra Zebra år ängel ögrupp

UTF-16 ⇔ UTF-32 ⇔ UTF-8 的转换可以仅通过位运算来实现。对于与任何其他编码的转换(不包括 ASCII,它是 Unicode 的一个子集),我会推荐一个库,例如libiconv .

关于c++ - 非 ascii 字符的字典顺序排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58886724/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com