在分割时捕获以“[[”并以“]]”开头的所有字符串作为正则表达式

时间:2012-05-01 18:13:21

标签: java regex scala

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

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

示例:

[[Genghis Khan]] 

应保持为

[[Genghis Khan]]

我应该使用什么样的正则表达式?

3 个答案:

答案 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中也显示了解析器)。