如何处理字符串中的自定义标签并记录有关格式的信息

时间:2019-04-22 07:41:52

标签: regex algorithm scala parsing

为我提供了以下格式的字符串:

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")]

注意,索引已更改,因为标签已被删除

我应该如何编写此算法?

1 个答案:

答案 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))

请注意,这些是每个文本范围的“从”(包含)和“直到”(不含)索引位置。