比较大小为 3 个字符的字符串

问题描述 投票:0回答:1

我正在尝试验证字符串(string_view)是否是“允许的”组合之一。

字符串是 always 3 个 ASCII 字符 - 大写和小写 - A、B、C。这些是 3 个元素的排列。

2个元素的功能相同,以后可以有4个元素的版本。

validate
的输入字符串是用户指定的。它可以是任何东西。

目前正在考虑这样的事情:

    constexpr uint32_t s2u(std::string_view s){
        using T = uint32_t;

        return
            (T(s[0]) << 8 * 0) |
            (T(s[1]) << 8 * 1) |
            (T(s[2]) << 8 * 2) ;
    }

    bool validate(std::string_view s){
        if (s.size() != 3)
            return false;

        switch( s2u(s) ){
        case s2u("abc") : case s2u("ABC") :
        case s2u("acb") : case s2u("ACB") :
        case s2u("bac") : case s2u("BAC") :
        case s2u("bca") : case s2u("BCA") :
        case s2u("cab") : case s2u("CAB") :
        case s2u("cba") : case s2u("CBA") : return true;
        default:
            return false;
        }
    }

有没有更快的方法?

C 解决方案也受欢迎。


更新

这是我更新的代码。我还决定将返回类型更改为 string_view 以便始终变为大写。

这在快速 C++ 基准测试中似乎也快得多。

我不关心字节序,因为我不需要大字节序和小字节序函数来生成相同的代码。我只关心回报是否正确。

    constexpr static auto s2u(std::string_view s){
        using T = uint32_t;

        auto _ = [s](uint8_t i){
            char const up = 0x20;

            return T(s[i] | up) << 8 * i;
        };

        return _(0) | _(1) | _(2);
    }

    std::string_view validateIndex(std::string_view s){
        if (s.size() != 3)
            return "";

        switch( s2u(s) ){
        case s2u("ABC") : return "ABC";
        case s2u("ACB") : return "ACB";
        case s2u("BAC") : return "BAC";
        case s2u("BCA") : return "BCA";
        case s2u("CAB") : return "CAB";
        case s2u("CBA") : return "CBA";
        default:
            return "";
        }
    }
c++ hash c++17
1个回答
0
投票

有些肮脏但可能更快的方法是预先计算一个大小为

128
(ASCII 表大小)的数组,该数组用零填充,除了与必须具有非零唯一值的允许字符相对应的索引值。

是的...这是一张没有地图的地图:D

然后您可以根据允许序列的数组值使用基于总和的哈希,并与

std::string_view
元素进行比较。

例如:

namespace
{
    constexpr int hmap[128] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                               0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
                               2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,5,
                               6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
}

bool validate(std::string_view sv)
{
    if(sv.size() != 3)
        return false;

    int val = hmap[static_cast<int>(sv[0])]
            + hmap[static_cast<int>(sv[1])]
            + hmap[static_cast<int>(sv[2])];

    return (val == 6) || (val == 15);
}

一种更具可读性的方法可能是创建一个初始化为零的数组,并仅在

main()
的开头分配 6 个有用的值。

© www.soinside.com 2019 - 2024. All rights reserved.