7

我目前正在使用扫描仪和解析器,需要一个解析器来接受 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

4 回答 4

17

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

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

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

def isAscii(c: Char) = c.toInt <= 127
于 2013-03-15T22:42:52.237 回答
2

不管你最终选择什么,我建议将“是一个 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)
}

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

于 2013-03-15T21:55:39.257 回答
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
于 2013-03-15T18:55:11.710 回答
-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)
于 2013-03-15T20:37:02.513 回答