Как обрабатывать пользовательские теги в строке и записывать информацию о форматировании - PullRequest
1 голос
/ 22 апреля 2019

Мне дают строку в следующем формате:

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 голосов
/ 22 апреля 2019

Итак, вот один из способов.

Начнем с определения местоположения всех тегов в необработанном тексте.

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

Обратите внимание, что это местоположения индексов «от» (включительно) и «до» (исключая) для каждого диапазона текста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...