目前我正在使用str.toLowerCase.split("[\\s\\W]+")
来摆脱空格和标点符号,但是我想保留一个特殊类别的字符串,并将其排除在此处理之外:
[[...multiple words...]]
示例:
[[Genghis Khan]]
应保持为
[[Genghis Khan]]
我应该使用什么样的正则表达式?
答案 0 :(得分: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 parser combinators的一个很好的用例,但是:
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)
我更喜欢解析器组合版本,个人 - 它实际上是自我记录的,并且更容易扩展和维护。
答案 1 :(得分:0)
这是一个首先在[[
或]]
上拆分的功能。这样做可以确保拆分项在未加引号和引用的字符串之间交替(即,第2,第4等项目被“引用”)。然后我们可以遍历这个列表并在空格上拆分任何未加引号的项目,同时保持引用的项目不变。
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 + "]]")
答案 2 :(得分:0)
Split不是处理此问题的方法,因为它不处理上下文。你可能写过:
str.toLowerCase.split("(?<!\\[\\[([^]]|\\][^]])*\\]?)[\\s\\W]+")
会在[[
之后的任何空格上分割,后跟除]]
之外的任何空格,但Java不喜欢可变大小的后视广告。
在我看来,处理这个的最好方法是为它编写一个解析器,除非你真的需要速度。使用Travis Brown建议的正则表达式(他在answer中也显示了解析器)。