在Scala中检查字符是否为ASCII字母(a-Z)的优雅方法是什么?

时间:2013-03-15 18:34:34

标签: scala ascii

我目前正在使用扫描仪和解析器,需要一个接受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的解决方案?我并不担心性能,因为在这种情况下并不重要。

4 个答案:

答案 0 :(得分:16)

你说你不能使用Char.isLetter因为你只想要ASCII字母。为什么不将它限制为7位ASCII字符范围?

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

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

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

答案 1 :(得分:2)

无论你最终选择什么,我建议为了可读性和性能而抽象出“是一个ASCII字母”的定义。 E.g:

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)
}

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

答案 2 :(得分:0)

第二个可以写成:

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

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

或者,如果你对++感到害怕,那几乎不是简单的英语:

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

答案 3 :(得分:-1)

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

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

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