【问题标题】:How to encode a constraint on the format of String values如何编码对字符串值格式的约束
【发布时间】:2011-08-27 19:47:23
【问题描述】:

正如我经常观察到的以及我经常实现name 属性的方式,将其简单地建模为String

如果名称必须遵循某种语法(即格式),现在该怎么办?在 Java 中,我可能会定义一个构造函数并检查其参数,例如:

public Name(str: String) {
    if (str == null) throw new IllegalArgumentException("Str must not be null.");
    if (!str.matches("name format expressed as regex")) throw new IllegalArgumentException("Str must match 'regex' but was " + str);
    this.str = str;
}

在 Scala 中,我提出了以下解决方案:

import StdDef.Str
import StdDef.Bol
import StdDef.?

import scala.util.parsing.combinator.RegexParsers

final case class Name private (pfx: ?[Str] = None, sfx: Str) {

  override def toString = pfx.mkString + sfx

}

object Name extends RegexParsers {

  implicit def apply(str: Str): Name = parseAll(syntax, str) match {
    case Success(res, _) => Name(res._1, res._2)
    case rej: NoSuccess => error(rej.toString)
  }

  lazy val syntax = (prefix ?) ~! suffix

  lazy val prefix = (("x" | "X") ~! hyph) ^^ { case a ~ b => a + b }

  lazy val suffix = alpha ~! (alpha | digit | hyph *) ^^ { case a ~ b => a + b.mkString }

  lazy val alpha: Parser[Str] = """\p{Alpha}""".r

  lazy val digit: Parser[Str] = """\p{Digit}""".r

  lazy val hyph: Parser[Str] = "-"

  override lazy val skipWhitespace = false

}

我的意图是:

  1. 根据其自然表示组成Name,即String
  2. 在构造时检查其自然表示是否形成有效的Name
  3. 不允许通过工厂方法apply:(str:Str)Str以外的任何其他构造。
  4. 从其自然表示中隐含构造,例如val a: Name = "ISBN 978-0-9815316-4-9"
  5. 根据其句法元素将Name 分解成各个部分。
  6. 消息中出现错误,例如:

===

--
^
[1.3] error: string matching regex `\p{Alpha}' expected but end of source found

我想知道您想出什么解决方案。

在对这个话题进行了更多思考之后,我目前正在采取以下方法。

Token.scala:

abstract class Token {
  val value: Str
}
object Token {
  def apply[A <: Token](ctor: Str => A, syntax: Regex) = (value: Str) => value match {
    case syntax() => ctor(value)
    case _ => error("Value must match '" + syntax + "' but was '" + value + "'.")
  }
}

Tokens.scala:

final case class Group private (val value: Str) extends Token
final case class Name private (val value: Str) extends Token
trait Tokens {
  import foo.{ bar => outer }
  val Group = Token(outer.Group, """(?i)[a-z0-9-]++""".r)
  val Name = Token(outer.Name, """(?i)(?:x-)?+[a-z0-9-]++""".r)
}

【问题讨论】:

    标签: regex parsing scala syntax combinators


    【解决方案1】:

    鉴于您会习惯在 Java 中使用正则表达式,然后尝试使用 Scala 中的解析器解决同样的问题似乎有点矫枉过正。

    坚持你在这里所知道的,但添加一个 Scala 扭曲以稍微清理解决方案。 Scala 中的正则表达式还定义了提取器,允许在模式匹配中使用它们:

    //triple-quote to make escaping easier, the .r makes it a regex
    //Note how the value breaks normal naming conventions and starts in uppercase
    //This is to avoid backticks when pattern matching
    
    val TestRegex = """xxyyzz""".r
    
    class Name(str: String) {
      str match {
        case Null => throw new IllegalArgumentException("Str must not be null")
        case TestRegex => //do nothing
        case _ => throw new IllegalArgumentException(
          "Str must match 'regex' but was " + str)
      }
    }
    

    免责声明:我并没有实际测试此代码,它可能包含拼写错误

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 2010-11-07
      • 2016-12-06
      • 2020-12-04
      • 1970-01-01
      • 2012-04-20
      • 2018-12-24
      相关资源
      最近更新 更多