为我提供了以下格式的字符串:
Lorem ipsum dolor <a>Hello <b>Nested</b> World</a> sit amet, consectetur
然后我使用正则表达式解析标签,并获得所有匹配项的数组,在这种情况下:
val text = "..."
val listOfRegexes = List[Regex](...)
val allMatches = listOfRegexes
.flatmap(
r => r
.findAllMatchIn(text)
.toList
.map(m => (m.start, m.end, "..."))
)
println(allMatches) // [(18, 49, "a"), (27, 39, "b")]
最终目标是从字符串中删除标签:
Lorem ipsum dolor Hello Nested World sit amet, consectetur
并创建一个描述格式的元组/对象列表,在这种情况下,它应如下所示:
[(18, 35, "a"), (24, 29, "b")]
注意,索引已更改,因为标签已被删除
我应该如何编写此算法?
答案 0 :(得分:0)
所以这是解决问题的一种方法。
我们将从在原始文本中找到所有标签开始。
val text =
"Lorem ipsum dolor <a>Hello <b>Nested</b> World</a> sit amet, consectetur"
val tags = "<([^>]+)>".r.findAllMatchIn(text)
.map(m => (m.start,m.end-m.start,m.group(1)))
.toList
//tags: List[(Int, Int, String)] = List((18,3,a), (27,3,b), (36,4,/b), (46,4,/a))
现在我们有了所有标记的位置和长度,可以按顺序整理文本。
val cleanTxt = tags.foldLeft((text,0)){
case ((str,acc),(x,len,_)) => (str.patch(x-acc,"",len),acc+len)
}._1
//cleanTxt: String = Lorem ipsum dolor Hello Nested World sit amet, consectetur
将标记的开始/结束位置进行配对(根据其在纯文本字符串中的位置进行调整)比较麻烦。
val cleanTags = tags.foldLeft((List.empty[(Int,String)],0)){
case ((lst,acc),(x,l,n))=> ((x-acc,n)::lst,acc+l)
}._1.reverse
//cleanTags: List[(Int, String)] = List((18,a), (24,b), (30,/b), (36,/a))
def pairTags(ts :Vector[(Int,String)]
,acc :List[(Int,Int,String)] = List()
) :List[(Int,Int,String)] =
if (ts.isEmpty) acc.reverse
else {
val hd = ts.head
val matchX = ts.lastIndexWhere(_._2 == "/" + hd._2)
assert(matchX > 0, "bad tag collection")
pairTags(ts.tail.patch(matchX-1,Vector(),1)
,(hd._1,ts(matchX)._1,hd._2) :: acc)
}
pairTags(cleanTags.toVector)
//res0: List[(Int, Int, String)] = List((18,36,a), (24,30,b))
请注意,这些是每个文本范围的“从”(包含)和“直到”(不含)索引位置。