【问题标题】:How do I check if a character is in a given range of characters?如何检查一个字符是否在给定的字符范围内?
【发布时间】:2014-05-21 07:47:44
【问题描述】:

C++:我如何检查一个字符是否在给定的字符范围之间?

说,如果我有一个字符串名称。 我想检查这个字符串的第一个字符是否在'a'到'n'之间。

我该怎么做?

要做 (name[0] == 'a') (name[0] == 'b')... 太长了...

如果可能的话,我想要一个优雅地处理 ASCII 值的解决方案。

【问题讨论】:

  • 作为评论,我确定这个问题之前已经被问过,但我尝试搜索了很长时间。没有。告诉我它是否重复。
  • 如果你想要完全的可移植性,你将不得不单独检查它们(尽管你可以通过使用“abcdef...klmn”来简化它)。如果您假设使用 ASCII,只需使用 .
  • 你在烦恼什么?获取第一个字符,还是比较它?告诉我们你写了什么。
  • @kingboonz:您真的应该阅读基本的 C++ 运算符和控制结构。您将需要它们来完成更多任务。

标签: c++ ascii


【解决方案1】:

如果您想检查字符串的第一个字符是否在 'a' 和 'n' 之间,例如,检查 name[0] >= 'a' && name[0] <= 'n' 应该可以正常工作。

但请记住,如果您的字母中的第一个字符也可以使用大写字母,则必须改为检查 (name[0] >= 'a' && name[0] <= 'n') || (name[0] >= 'A' && name[0] <= 'N')

【讨论】:

  • 你能提供一个支持它的参考吗? This answer 说 C++ 只保证 C 做什么,即十进制数字。
  • 您的链接似乎表明字母不必按顺序排列,这是我不知道的。这样做对我来说一直很成功,但我想我不能保证它会在任何地方都有效。我认为它应该适用于大多数机器,这就是我建议它的原因。
  • 要比较大写字母,可以将字符转换为大写或小写并仅使用一次比较。
  • @ThomasMatthews:这确实是另一种方法,更容易阅读。我不确定它是否更有效,但它肯定更干净:)
  • 值得注意的是,这对 ASCII 很有效,因为拉丁字母在 ASCII 中占据顺序空间,但它不适用于 EBCDIC 或 UTF-16 甚至 UTF-8 的非拉丁部分.这个问题专门询问 ASCII,所以这应该可以解决问题。请注意。
【解决方案2】:

您可以将std::all_oflambda expression 结合使用:

std::all_of(name.begin(), name.end(), [](char i) { return (i >= 'a' && i <= 'z'); });

Live demo

这对于大多数应用程序来说足够便携,因为字符集通常是按照 ASCII 约定实现的,如 §2.3/14 中所述:

基本源字符集成员的字形旨在识别对应于 ASCII 字符集的 ISO/IEC 10646 子集中的字符。但是,由于从源文件字符到源字符集的映射(在翻译阶段 1 中描述)被指定为实现定义,因此需要一个实现来记录基本源字符在源文件中的表示方式。

上述算法的复杂度为O(n)。另一种选择(使用k 字符检查字符范围内的每个字符)是O(n*k),但至少您可以确定它不是实现定义的。

【讨论】:

    【解决方案3】:

    如果您确定在您的平台上使用的字符集是 ASCII,您可以使用类似:

    if (std::all_of(name.begin(), name.end(), [](char c){return ((c >= 'a') && (c <= 'n'));}) ) {
        // name contains only characters between 'a' and 'n' inclusive
    }
    

    否则,这样的事情应该可以解决问题:

    if (name.find_first_not_of("abcdefghijklmn") == std::string::npos) {
        // name contains only characters between 'a' and 'n' inclusive
    }
    

    【讨论】:

      【解决方案4】:

      一种老式的便携方法:

          bool is_in_range(char range_start, char range_end, char c)
          {
            static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
            unsigned int start_position = 0;
            unsigned int end_position = 0;
            unsigned int character_position = 0;
            c = std::tolower(c);
            for (unsigned int i = 0; i < sizeof(alphabet); ++i)
            {
               if (range_start == alphabet[i])
               {
                  start_position = i;
               }
               if (range_end == alphabet[i])
               {
                  end_position = i;
               }
               if (c == alphabet[i])
               {
                  character_position = i;
               }
            }
            bool result = false;
            if (end_position <= start_position)
            {
              result = false;
            }
            else
            {
              if ((character_position >= start_position) && (character_position <= end_position))
              {
                result = true;
              }
            }
            return result;
      }
      

      【讨论】:

        【解决方案5】:

        遍历字符串,检查每个字符,看看它是否停留在 a 和 n 之间,使用 str[i]>'a' 和 str[i]

        【讨论】:

        • 那么这行得通吗? if ('a'
        • @kingboonz 你是否包含了字符串库?我想知道你是否可以包括更多细节?
        【解决方案6】:

        对于连续的字符范围,您可以:

        _Bool isbetween(int c, int start, int end){
          return ((unsigned)c-start < (end-start));
        }
        

        要考虑大小写,请使用tolower() 和小写范围:

        static inline int tolower(int c){
          return c | ( ((unsigned)c-'A' < 26)<<5 );
        }
        //isbetween(tolower(x),'a','n');
        

        对于非连续范围,您可能需要创建掩码。在这个例子中,我将检查元音(为简洁起见,因为只有 5 个,但可以使用 32 范围内的任何组合或 64 进行一些修改...... 事实上,64 位平台上的 64 位掩码将消除对大小写处理的需要)。

        static const unsigned vowel_mask =  (1<<('a'-'a'))
          |(1<<('e'-'a'))|(1<<('i'-'a'))|(1<<('o'-'a'))|(1<<('u'-'a'));
        
        int isvowel(int c){ //checks if c is a,A,e,E,i,I,o,O,u,U 
          unsigned x = (c|32)-'a';
          return ((x<32)<<x)&vowel_mask;
        }
        

        请注意,这些实现不包含分支;但是,使用无符号比较可能会阻止自动编译器矢量化(英特尔内在函数,没有无符号比较)......如果这是您的目标,您可以使用 2 &amp;ed 比较来代替。根据字符的间隔距离,此方法可能适用于非 ascii 系统,也可能不适用。

        海合会

        isvowel:
                or      edi, 32     # tmp95,
                xor     eax, eax  # tmp97
                sub     edi, 97   # x,
                cmp     edi, 31   # x,
                setbe   al    #, tmp97
                shlx    eax, eax, edi   # tmp99, tmp97, x
                and     eax, 1065233      # tmp96,
                ret
        

        叮当

        isvowel: # @isvowel
          or edi, 32
          add edi, -97
          mov eax, 32
          xor ecx, ecx
          cmp edi, eax
          setb cl
          shlx eax, ecx, edi
          and eax, 1065233
          ret
        

        国际商会

        isvowel:
          xor eax, eax #15.26
          or edi, 32 #14.23
          add edi, -97 #14.27
          cmp edi, 32 #15.26
          setb al #15.26
          shlx eax, eax, edi #15.23
          and eax, 1065233 #15.26
          ret #15.26
        

        除了标准的 stackoverflow 许可,此代码已发布到公共领域

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-06-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-15
          • 1970-01-01
          • 2023-02-21
          相关资源
          最近更新 更多