【问题标题】:What is an elegant way to check if a character is an ASCII letter (a-Z) in Scala?在 Scala 中检查字符是否为 ASCII 字母(a-Z)的优雅方法是什么?
【发布时间】:2013-03-04 14:26:49
【问题描述】:

我目前正在使用扫描仪和解析器,需要一个可以接受 ASCII 字母字符的解析器 - 所以我不能使用 char.isLetter

我自己想出了两个解决方案。两个我都不喜欢。

正则表达式

def letter = elem("ascii letter", _.toString.matches("""[a-zA-Z]"""))

用正则表达式检查这样一个简单的事情似乎有点“矫枉过正”。

范围检查

def letter = elem("ascii letter", c => ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))

在我看来,这将是 Java 的发展方向。但它不是真的可读。

对于这个问题,是否有更简洁、更类似于 Scala 的解决方案?我并不担心性能,因为在这种情况下并不重要。

【问题讨论】:

  • 我觉得正则表达式没问题。如果担心性能,只需创建/保留正则表达式对象 .. 否则,提供性能测试用例。简单的正则表达式可以 fast (即使使用 toString)来应用;它们可以通过回溯退化,这在此处不适用。
  • 我只是觉得这个正则表达式一点也不优雅。使用 Scala 时,感觉可以做很多非常棒的事情。但是这个好像不是这样的。
  • 我觉得正则表达式很优雅,因为它是一种特定领域的语言,非常适合这个特定任务:描述特定字符串输入必须遵守的基于字符的语法。正则表达式适用于很多事情,但除非现有方法或已知性能问题,否则我会使用正则表达式而不会三思而后行。跨度>

标签: scala ascii


【解决方案1】:

第二个可以写成:

def letter = elem("ascii letter", c => ('a' to 'z') ++ ('A' to 'Z') contains c)

它更具可读性,但性能较差。

或者,如果你对 ++ 感到害怕,就像简简单单的英语:

c => ('a' to 'z') union ('A' to 'Z') contains c

【讨论】:

    【解决方案2】:

    另一个 - 很好 - 优雅的解决方案可能是使用 min/max:

    c => 'A'.max(c.toUpper) == 'Z'.min(c.toUpper)
    

    c => 'A'.max(c) == 'Z'.min(c) || 'a'.max(c) == 'z'.min(c)
    

    【讨论】:

    • 没有冒犯,但在我看来,它隐藏了一个原始意图,从而使代码混乱(虽然这可能是简洁和聪明的)。实际上,如果我们将我们的解决方案结合起来,我们可能会得到类似 'a' to 'z' contains c.toLower 的东西,我个人更喜欢它。
    • 是的 - 这看起来很聪明 - 但是,它的效率有点低,不是吗? ;)
    • 是的,在紧密的循环中会非常低效
    • 好的 - 所以你也可以将它添加到你的解决方案中:) - 我正在考虑一些减法,但现在这变得太奇怪了。
    【解决方案3】:

    无论你最终选择什么,我建议将“是一个 ASCII 字母”的定义抽象出来,以提高可读性和性能。例如:

    object Program extends App {
      implicit class CharProperties(val ch: Char) extends AnyVal {
        def isASCIILetter: Boolean =
          (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
      }
      println('x'.isASCIILetter)
      println('0'.isASCIILetter)
    }
    

    或者如果您想将 ASCII 字母描述为一组:

    object Program extends App {
      object CharProperties {
        val ASCIILetters = ('a' to 'z').toSet ++ ('A' to 'Z').toSet
      }
      implicit class CharProperties(val ch: Char) extends AnyVal {
        def isASCIILetter: Boolean =
          CharProperties.ASCIILetters.contains(ch)
      }
      println('x'.isASCIILetter)
      println('0'.isASCIILetter)
    }
    

    一旦您使用具有可理解名称的显式函数,无论哪种方式,您的意图都应该是明确的,并且您可以选择性能更好的实现(尽管上述两个版本之间的任何性能差异应该很小)。

    【讨论】:

    • 感谢这个,没想到隐式转换为“添加”我的isASCIILetter 方法。
    【解决方案4】:

    您说您不能使用Char.isLetter,因为您只需要ASCII 字母。为什么不将其限制在 7 位 ASCII 字符范围内?

    def isAsciiLetter(c: Char) = c.isLetter && c <= 'z'
    

    如果读者想要检查包含非字母的 ASCII,那么:

    def isAscii(c: Char) = c.toInt <= 127
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 2019-09-26
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 2013-09-11
    • 2018-03-16
    相关资源
    最近更新 更多