如何检查一个字符是否在给定的一段字符范围内?

11

C ++:如何检查字符是否在给定的一组字符范围内?

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

我该怎么做?

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

如果可能,我希望有一种可以优雅地处理ASCII值的解决方案。


作为评论,我确信这个问题以前已经被问过了,但是我尝试搜索了很长时间也没有找到。如果它是重复的,请告诉我。 - kingboonz
1
尝试一下:http://www.cplusplus.com/reference/string/string/compare/ - Ben
@kingboonz:你真的应该学习基本的C++运算符和控制结构。这些对于许多其他任务都是必需的。 - Deduplicator
(name[0] == 'a' || name[0] == 'b' || ... ||| name[0] =='n') - kingboonz
所以我可以使用这个吗?if ('a'<=name[1] && name[1]<='n') ??? 这在C++中合法吗? - kingboonz
显示剩余2条评论
6个回答

12

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

然而,请注意,如果您的字母的第一个字符也可能是大写的,则必须检查 (name[0] >= 'a' && name[0] <= 'n') || (name[0] >= 'A' && name[0] <= 'N')


你能提供一个支持这个观点的参考资料吗?这个回答说C++只保证了C所保证的,也就是十进制数字。 - unwind
您的链接似乎表明字母不必按顺序排列,这是我以前不知道的。用这种方式一直对我很成功,但我想我不能保证它在任何地方都能起作用。不过我认为它应该在大多数机器上都能工作,这就是我建议它的原因。 - Dex
为了比较大写字母,可以将字符转换为大写或小写,并仅使用一个比较。 - Thomas Matthews
@ThomasMatthews:这确实是另一种更易于阅读的方法。我不确定它是否更高效,但肯定更加简洁 :) - Dex
1
值得注意的是,这对ASCII很有效,因为拉丁字母在ASCII中占据了连续的空间,但它不适用于EBCDIC或UTF-16甚至UTF-8的非拉丁部分。问题特别提到了ASCII,所以这应该能解决问题。只要注意这一点即可。 - Bill Weinman

3
你可以使用std::all_oflambda表达式结合使用:
std::all_of(name.begin(), name.end(), [](char i) { return (i >= 'a' && i <= 'z'); });

实时演示

由于字符集通常遵循ASCII约定(如第2.3/14节所述),因此这对大多数应用程序来说是足够便携的:

基本源字符集成员的字形旨在识别与ASCII字符集对应的ISO/IEC 10646子集中的字符。然而,由于从源文件字符到源字符集的映射(在转换阶段1中描述)被指定为实现定义,因此必须记录实现如何在源文件中表示基本源字符。

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


2

如果您确定平台上使用的字符集为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
}

1
一种老式的便携方法:
    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;
}

0

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

_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个&比较代替。该方法在非ASCII系统上可能有效,具体取决于字符之间的分隔距离。
GCC
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

Clang

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

ICC

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许可证外,此代码已发布到公共领域


0

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


这样会行吗?如果('a'<=name[1] && name[1]<='n') 我需要声明任何库吗?我编译时遇到了麻烦。它给我1页的错误,当我删除它时,它就可以编译了。 - kingboonz
@kingboonz 你有包含字符串库吗?我想知道你能否提供更多细节信息? - user3360398

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接