【问题标题】:Detecting if a string is all CAPS检测字符串是否全部大写
【发布时间】:2010-10-01 16:24:18
【问题描述】:

在 C# 中有没有办法检测字符串是否全部大写?

大部分字符串都很短(即少于 100 个字符)

【问题讨论】:

  • 在你的循环中,一旦你找到一个小写字符,就没有必要继续了,因为它已经通过了测试
  • 当它看到一个非字母时,你希望结果是什么,例如标点符号还是空格? ToUpper 解决方案返回 true;问题返回 false。
  • if(!Char.IsLetter(input[i]) || Char.IsUpper(input[i])) { etc }
  • 类似于这个问题:stackoverflow.com/questions/234591/upper-vs-lower-case。文化会发挥作用吗?如果是这样,则接受的答案不正确。
  • 出于我的目的,当包含非字母字符时,我需要它返回 true。因此,当它评估 ABC1 不为假时,我需要它为真。我已经尝试了这两种解决方案,在这种情况下,ToUpper 更适合我的需求。

标签: c# string


【解决方案1】:

您还可以调用 Windows 函数来告诉您字符串的构成。

GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, s, s.Length, ref characterTypes);

您为其提供一个与字符串长度相同的UInt16 数组,并使用标志的按位组合填充每个元素:

  • C1_UPPER (0x0001): 大写
  • C1_LOWER (0x0002): 小写
  • C1_DIGIT (0x0004):十进制数字
  • C1_SPACE (0x0008): 空格字符
  • C1_PUNCT (0x0010): 标点符号
  • C1_CNTRL (0x0020):控制字符
  • C1_BLANK (0x0040): 空白字符
  • C1_XDIGIT (0x0080): 十六进制数字
  • C1_ALPHA (0x0100):任何语言字符:字母、音节或表意。有些字符可以是字母而不是大写或小写
  • C1_DEFINED (0x0200):定义的字符,但不是其他 C1_* 类型之一

所以如果你检查了字符串:

你好,“42”!

你会得到结果

[0x210, 0x301, 0x382, 0x302, 0x302, 0x302, 0x210, 0x248, 0x210, 0x284, 0x284, 0x210, 0x210]

分解为:

|            | H | e | l | l | o | , |   | " | 4 | 2 | " | ! |
|------------|---|---|---|---|---|---|---|---|---|---|---|---|
| Defined    | X | X | X | X | X | X | X | X | X | X | X | X |
| Alpha      | x | x | x | x | x |   |   |   |   |   |   |   |
| XDigit     |   | x |   |   |   |   |   |   | x | x |   |   |
| Blank      |   |   |   |   |   |   | x |   |   |   |   |   |
| Cntrl      |   |   |   |   |   |   |   |   |   |   |   |   |
| Punct      |   |   |   |   |   | x |   |   |   |   | x | x |
| Space      |   |   |   |   |   |   | x |   |   |   |   |   |
| Digit      |   |   |   |   |   |   |   |   | x | x |   |   |
| Lower      |   | x | x | x | x |   |   |   |   |   |   |   |
| Upper      | x |   |   |   |   |   |   |   |   |   |   |   |

【讨论】:

    【解决方案2】:

    另一种方法

    return input.Equals(input.ToUpper(), StringComparison.Ordinal)
    

    【讨论】:

      【解决方案3】:

      我喜欢 LINQ 方法。

      如果您想将其限制为所有大写字母(即没有空格等):

      return input.All(c => char.IsUpper(c));
      

      或使用方法组转换:

      return input.All(char.IsUpper);
      

      如果你只想禁止小写字母:

      return !input.Any(c => char.IsLower(c));
      

      return !input.Any(char.IsLower);
      

      【讨论】:

      • 看起来c => c.IsUpper(c) 不再有效(至少在 VS2013 中):错误 CS0176:无法使用实例引用访问成员 'char.IsUpper(char)';改为使用类型名称来限定它
      • @Joce:那永远不会有效 - 这是一个错字。现已修复,谢谢。
      【解决方案4】:

      确保您的大写定义与 .Nets 的大写定义相匹配。

      .Net 中的 ToUpper() 是一种语言操作。在某些语言中,大小写规则并不直接。 Turkish I is famous for this

      // Meaning of ToUpper is linguistic and depends on what locale this executes
      // This test could pass or fail in ways that surprise you.
      if (input.ToUpper() == input) 
      {
          // string is all upper
      }
      

      你可以使用

      // Meaning of ToUpper is basically 'ASCII' ToUpper no matter the locale.
      if (input.ToUpper(CultureInfo.InvariantCulture) == input) 
      {
          // string is all upper
      }
      

      你可能想通过字符大写来节省内存

      MSDN cautions against this

      for(int i = 0; i < input.Length; i++) {
         if(input[i] != Char.ToUpper(input[i], CultureInfo.InvariantCulture)) {
           return false;
         }
      }
      

      上面的代码引入了一个错误。一些非英语“字母”需要两个 .net 字符来编码(代理对)。您必须检测这些对并将它们大写为一个单元。

      此外,如果您省略文化信息以获取语言大写,您将引入一个错误,即在某些语言环境中,您的自制大写算法与该语言环境的 .net 算法不一致。

      当然,如果您的代码永远不会在英语语言环境之外运行或永远不会收到非英语文本,那么这些都不重要。

      【讨论】:

        【解决方案5】:

        无需创建新字符串:

        bool IsAllUpper(string input)
        {
            for (int i = 0; i < input.Length; i++)
            {
                if (!Char.IsUpper(input[i]))
                     return false;
            }
        
            return true;
        }
        

        编辑:如果您想跳过非字母字符(OP 的原始实现不会,但他/她的 cmets 表示他们可能想要):

           bool IsAllUpper(string input)
            {
                for (int i = 0; i < input.Length; i++)
                {
                    if (Char.IsLetter(input[i]) && !Char.IsUpper(input[i]))
                        return false;
                }
                return true;
            }
        

        【讨论】:

        • 这个解决方案比公认的解决方案(恕我直言)更好,因为它不需要创建不必要的字符串。这可能是更多的代码行,但这并不总是一件坏事。
        • 你赢了一些,你输了一些。我不敢相信接受的答案收到了多少 +1。
        • 我同意,这个答案比任何基于 .ToUpper() 的答案都要好。
        • 或者 if (input.All(Char.IsUpper) { }
        • 当你可以用一行断言一个简单的正则表达式匹配时,我不明白为什么还有一个 10 行函数... Google 叔叔告诉我 like @987654323 @ 应该可以工作...或者...检查 [az] 并且应该没有匹配项(如果允许输入非字母字符)¯_(ツ)_/¯
        【解决方案6】:

        想到正则表达式。在那里找到这个:http://en.csharp-online.net/Check_if_all_upper_case_string

        【讨论】:

          【解决方案7】:

          我认为如下:

          bool equals = (String.Compare(input, input.ToUpper(), StringComparison.Ordinal) == 0)
          

          也可以,您可以确保在不考虑字符串大小写的情况下进行比较(我认为 VB.NET 默认情况下会忽略大小写)。 O 甚至使用String.CompareOrdinal(input, input.ToUpper())

          【讨论】:

          • 至少在 C# 中, == 使用 String.Equals() 这是一个序数比较。
          • VB.Net 绝对不会忽略字符串比较的大小写
          • 谢谢 Jon 和 Joel 的澄清。
          • @JoelCoehoorn * VB.Net 默认不忽略大小写。如果您使用“选项比较文本”,它将忽略字符串比较的大小写
          【解决方案8】:

          如果这需要有良好的性能,我假设它经常发生。如果是这样,请采用您的解决方案并执行几百万次并计时。我怀疑你所拥有的比其他解决方案更好,因为你没有创建一个必须清理的新垃圾收集对象,而且你不能在不迭代字符串的情况下复制它。

          【讨论】:

            【解决方案9】:

            使用

            if (input == input.ToUpper())
            

            【讨论】:

            • 这是最好的和最简单的...没有循环开销!
            【解决方案10】:

            简单吗?

            if (input.ToUpper() == input)
            {
                // string is all upper
            }
            

            【讨论】:

            • 我很高兴能得到一个简单的最佳答案,可惜你打败了我:(
            • 这会为“ABC1”或“*!()@”之类的字符串计算“真”。我不知道原始海报的上下文,但这个解决方案肯定会为包含非大写字母的字符串返回“真”。
            • 代码越少越好。一种方式是不必要地将其转换为上部,另一种方式是不必要地将简单的 == 转换为九行循环函数。如果分析表明它有帮助,则进行优化。
            • 我会选择 ToUpperInvariant()
            【解决方案11】:

            我会将字符串转换为全部大写(使用ToUpper),然后将其与原始字符串进行比较(使用Equals)。应该可以在一行代码中实现。

            return s.Equals(s.ToUpper())

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-11-12
              • 2020-04-05
              • 2014-08-13
              • 2018-01-03
              相关资源
              最近更新 更多