实现字符串到整数查找的快速且可维护的方法 table
Fast and maintainable way of implementing string to integer lookup table
我可以找到许多关于如何将整数映射到字符串常量的问题,以及明显的解决方案
char const* strings[] = {"Foo", "Bar", ...};
现在,假设我想要反转:我有字符串 "Bar",并且想要 1。我的字符串最多 4 个字符,ascii null 不是有效值。有 64 个整数可以将值映射到。我是否必须编写一个带有字符串比较的长 if-else 结构,还是有更好的方法。
为了澄清,我更喜欢不需要运行时初始化的解决方案,从 C++17 开始,这使得 ti 无法使用 std::map
或 std::unordered_map
。
你应该使用 std::map
除非你需要 better/custom。
std::map<std::string, int> stringToPos;
stringToPos["Foo"] = stringToPos.size(); // there's other ways to init the map, but you can fill it up this way too
stringToPos["Bar"] = stringToPos.size();
stringToPos["Bleh"] = stringToPos.size();
std::cout << stringToPos["Bleh"] << std::endl;
填充地图的另一个选项是:
for(auto s:{"foo","bar","bleh"})
{
stringToPos[s] = stringToPos.size();
}
如果您可以使用 c++17,我会使用带有 string_view
的 unordered_map
。像
#include <iostream>
#include <string_view>
#include <unordered_map>
int main(){
std::array<char const*,2> strings = { "Foo", "Bar" };
std::unordered_map<std::string_view,int> map;
for( int i = 0 ; i != strings.size(); ++i )
map[strings[i]] = i;
std::cout << map["Foo"];
}
查看工作版本 here:
My strings are up to 4 characters and ascii null is not a valid value.
在此条件下,您可以将字符串转换为整数,并使用您最喜欢的编译时整数到整数映射。
例如,switch
:
#include <cstddef>
#include <cstdint>
namespace detail {
constexpr std::uint64_t string_as_int(const char* string) noexcept {
std::uint64_t result = 0;
std::uint64_t i = 0;
for (; i < 4 && *string; ++string, ++i) {
result |= static_cast<std::uint64_t>(static_cast<unsigned char>(*string)) << (i * 8u);
}
return result;
}
constexpr std::uint64_t operator ""_h(const char* string, std::size_t) noexcept {
return string_as_int(string);
}
}
constexpr int lookup(const char* string) {
using detail::operator ""_h;
switch (detail::string_as_int(string)) {
case "Foo"_h: return 1;
case "Bar"_h: return 2;
default: return 0;
}
}
我可以找到许多关于如何将整数映射到字符串常量的问题,以及明显的解决方案
char const* strings[] = {"Foo", "Bar", ...};
现在,假设我想要反转:我有字符串 "Bar",并且想要 1。我的字符串最多 4 个字符,ascii null 不是有效值。有 64 个整数可以将值映射到。我是否必须编写一个带有字符串比较的长 if-else 结构,还是有更好的方法。
为了澄清,我更喜欢不需要运行时初始化的解决方案,从 C++17 开始,这使得 ti 无法使用 std::map
或 std::unordered_map
。
你应该使用 std::map
除非你需要 better/custom。
std::map<std::string, int> stringToPos;
stringToPos["Foo"] = stringToPos.size(); // there's other ways to init the map, but you can fill it up this way too
stringToPos["Bar"] = stringToPos.size();
stringToPos["Bleh"] = stringToPos.size();
std::cout << stringToPos["Bleh"] << std::endl;
填充地图的另一个选项是:
for(auto s:{"foo","bar","bleh"})
{
stringToPos[s] = stringToPos.size();
}
如果您可以使用 c++17,我会使用带有 string_view
的 unordered_map
。像
#include <iostream>
#include <string_view>
#include <unordered_map>
int main(){
std::array<char const*,2> strings = { "Foo", "Bar" };
std::unordered_map<std::string_view,int> map;
for( int i = 0 ; i != strings.size(); ++i )
map[strings[i]] = i;
std::cout << map["Foo"];
}
查看工作版本 here:
My strings are up to 4 characters and ascii null is not a valid value.
在此条件下,您可以将字符串转换为整数,并使用您最喜欢的编译时整数到整数映射。
例如,switch
:
#include <cstddef>
#include <cstdint>
namespace detail {
constexpr std::uint64_t string_as_int(const char* string) noexcept {
std::uint64_t result = 0;
std::uint64_t i = 0;
for (; i < 4 && *string; ++string, ++i) {
result |= static_cast<std::uint64_t>(static_cast<unsigned char>(*string)) << (i * 8u);
}
return result;
}
constexpr std::uint64_t operator ""_h(const char* string, std::size_t) noexcept {
return string_as_int(string);
}
}
constexpr int lookup(const char* string) {
using detail::operator ""_h;
switch (detail::string_as_int(string)) {
case "Foo"_h: return 1;
case "Bar"_h: return 2;
default: return 0;
}
}