2011-08-27 69 views
0

正如我經常觀察的以及我經常實現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) 
} 

回答

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

免責聲明:我沒有實際測試此代碼,它可能包含錯別字

相關問題