2

目前我正在使用str.toLowerCase.split("[\\s\\W]+")摆脱空白和标点符号,但有一类特殊的字符串我想保留并排除在这种处理之外:

[[...multiple words...]]

例子:

[[Genghis Khan]] 

应保持为

[[Genghis Khan]]

我应该使用哪种正则表达式?

4

3 回答 3

8

您的正则表达式并不遥远:

def tokenize(s: String) = """\w+|(\[\[[^\]]+\]\])""".r.findAllIn(s).toList

接着:

scala> tokenize("[[Genghis Khan]] founded the [[Mongol Empire]].")
res1: List[String] = List([[Genghis Khan]], founded, the, [[Mongol Empire]])

不过,这是 Scala 的解析器组合器的一个很好的用例:

import scala.util.parsing.combinator._

object Tokenizer extends RegexParsers {
  val punc = "[,;:\\.]*".r
  val word = "\\w+".r
  val multiWordToken = "[[" ~> "[^\\]]+".r <~ "]]"
  val token = (word | multiWordToken) <~ punc
  def apply(s: String) = parseAll(token+, s)
}

这同样给了我们:

scala> Tokenizer("[[Genghis Khan]] founded the [[Mongol Empire]].").get
res2: List[String] = List(Genghis Khan, founded, the, Mongol Empire)

我个人更喜欢解析器组合器版本——它实际上是自记录的,并且更容易扩展和维护。

于 2012-05-01T18:34:51.823 回答
0

拆分不是处理这个问题的方法,因为它不处理上下文。你可能这样写:

str.toLowerCase.split("(?<!\\[\\[([^]]|\\][^]])*\\]?)[\\s\\W]+")

它会在任何前面没有[[后面跟着除 之外的任何空间上拆分]],但 Java 不喜欢可变大小的后视。

在我看来,处理这个问题的最好方法是为它编写一个解析器,除非你真的需要速度。使用像Travis Brown建议的正则表达式(他还在他的回答中展示了一个解析器)。

于 2012-05-02T21:26:14.670 回答
0

[[这是一个首先在或上拆分的函数]]。这样做可确保拆分项在未引用字符串和引用字符串之间交替(即,第二个、第四个等项被“引用”)。然后我们可以遍历这个列表并在空白处拆分任何未引用的项目,同时保留引用的项目不变。

def mySplit(s: String) = 
  """(\[\[)|(\]\])""".r.split(s).zipWithIndex.flatMap { 
    case (unquoted, i) if i%2==0 => unquoted.trim.split("\\s+")
    case (quoted, _) => List(quoted)
  }.toList.filter(_.nonEmpty)

mySplit("this [[is]] the first [[test string]].") // List(this, is, the, first, test string, .)
mySplit("[[this]] and [[that]]")          // List(this, and, that)
mySplit("[[this]][[that]][[the other]]")  // List(this, that, the other)

如果你想[[ ]]在最终输出中,那么只需将上面的内容更改List(quoted)List("[[" + quoted + "]]")

于 2012-05-01T18:25:36.170 回答