2

应该使用 Scala 模式匹配和正则表达式逐行解析文本文件。如果一行以"names:\t"随后的制表符分隔名称开头,则应提供为Seq[String](或类似名称)。

这是一个非工作代码示例:

val Names = "^names:(?:\t([a-zA-Z0-9_]+))+$".r

"names:\taaa\tbbb\tccc" match {
  case Names(names @ _*) => println(names)
  // […] other cases
  case _ => println("no match")
}

输出:List(ccc)
想要的输出:List(aaa, bbb, ccc)

下面的代码可以按需要工作……</p>

object NamesObject {
  private val NamesLine = "^names:\t([a-zA-Z0-9_]+(?:\t[a-zA-Z0-9_]+)*)$".r

  def unapplySeq(s: String): Option[Seq[String]] = s match {
    case NamesLine(nameString) => Some(nameString.split("\t"))
    case _ => None
  }
}

"names:\taaa\tbbb\tccc" match {
  case NamesObject(names @ _*) => println(names)
  // […] other cases
  case _ => println("no match")
}

输出(根据需要):WrappedArray(aaa, bbb, ccc)

我想知道:这是否可以在不创建 的情况下以更简单的方式实现object,就像在第一个但不工作的代码示例中一样?

4

2 回答 2

1

使用您的工作正则表达式。(\w是一个预定义的字符类[a-zA-Z0-9_]

  val Names = """names:\t(\w+(?:\t\w+)*)""".r
  "names:\taaa\tbbb\tccc" match {
    case Names(names) => println(names.split("\t") toSeq)
    case _ => println("no match")
  }

使用第一、第二和尾部绑定,

  val Names = """names:\t(\w+)?\t?(\w+)?\t?((?:\w+?\t?)*)""".r
  "names:\taaa\tbbb\tccc\tddd" match {
    case Names(first, second, tail) =>
      println(first + ", " + second + ", " + (tail.split("\t") toSeq));
    case _ => println("no match")
  }
于 2013-03-26T15:28:54.687 回答
0

正如 Randall Schulz 所说,仅使用正则表达式似乎是不可能的。因此,我的问题的简短回答是否定的。

我目前的解决方案如下:我使用这个类...</p>

class SeparatedLinePattern(Pattern: Regex, separator: String = "\t") {
  def unapplySeq(s: String): Option[Seq[String]] = s match {
    case Pattern(nameString) => Some(nameString.split(separator).toSeq)
    case _ => None
  }
}

…创建模式:

val Names = new SeparatedLinePattern("""names:\t([A-Za-z]+(?:\t[A-Za-z]+)*)""".r)
val Ints = new SeparatedLinePattern("""ints:\t(\d+(?:\t\d+)*)""".r)
val ValuesWithID = new SeparatedLinePattern("""id-value:\t(\d+\t\w+(?:\t\d+\t\w+)*)""".r)

这是一个如何以非常灵活的方式使用它们的示例:

val testStrings = List("names:\taaa", "names:\tbbb\tccc", "names:\tddd\teee\tfff\tggg\thhh",
                       "ints:\t123", "ints:\t456\t789", "ints:\t100\t200\t300",
                       "id-value:\t42\tbaz", "id-value:\t2\tfoo\t5\tbar\t23\tbla")

for (s <- testStrings) s match {
  case Names(name) => println(s"The name is '$name'")
  case Names(a, b) => println(s"The two names are '$a' and '$b'")
  case Names(names @ _*) => println("Many names: " + names.mkString(", "))

  case Ints(a) => println(s"Just $a")
  case Ints(a, b) => println(s"$a + $b == ${a.toInt + b.toInt}")
  case Ints(nums @ _*) => println("Sum is " + (nums map (_.toInt)).sum)

  case ValuesWithID(id, value) => println(s"ID of '$value' is $id")
  case ValuesWithID(values @ _*) => println("As map: " + (values.grouped(2) map (x => x(0).toInt -> x(1))).toMap)

  case _ => println("No match")
}

输出:

The name is 'aaa'
The two names are 'bbb' and 'ccc'
Many names: ddd, eee, fff, ggg, hhh
Just 123
456 + 789 == 1245
Sum is 600
ID of 'baz' is 42
As map: Map(2 -> foo, 5 -> bar, 23 -> bla)
于 2013-03-27T09:03:29.257 回答