Удаление строк из списка массива между 2 указанными тегами

#java #arraylist

Вопрос:

Я пытаюсь удалить все элементы списка массива между начальным и конечным тегом.

Мой список и мои теги:

 String startTag = "<p>";
String endTag = "</p>";
List<String> elements = new ArrayList<>();

 

Допустим, мой список выглядит так:

 [<text>, <p>, <text>, clean me, </text>, </p>, </text>]
 

Я хочу удалить только содержимое между разделенными тегами и самими тегами.
Это мой код для этого:

        boolean delete = false;
       List<String> remove = new ArrayList<>();
        for(String element : elements) {
            if(delete) {
                remove.add(element);
            }

            if(element.startsWith(startTag)) {
                delete = true;
                remove.add(element);
            }
            if(element.endsWith(endTag)) {
                delete = false;
                remove.add(element);
            }
        }
        elements.removeAll(remove);
    }
 

Вот как выглядит мой список «удалить» после этого:

 [<p>, <text>, clean me, </text>, </p>, </p>]
 

Итак, после удаления этих элементов из моего списка это выглядит так:

 []
 

Когда это должно выглядеть так:

 [<text>, </text>]
 

Как я могу запретить удалять строки, у которых есть дубликаты, когда они находятся за пределами диапазона удаления?

Ответ №1:

Как я могу запретить удалять строки, у которых есть дубликаты, когда они находятся за пределами диапазона удаления?

Определяя диапазон для удаления по индексу элемента, а не по значению элемента. Есть много способов, которыми вы могли бы это сделать, но вот один, который мне нравится:

 List<String> remainingElements = elements;
List<String> result = new ArrayList<>();

for (int start = remainingElements.indexOf(startTag);
         start >= 0;
         start = remainingElements.indexOf(startTag)) {
    List<String> tail = remainingElements.subList(start, remainingElements.size());
    int end = tail.indexOf(endTag);

    if (end >= 0) {
        List<String> range = tail.subList(0, end   1);
        result.addAll(range);
        range.clear();
        remainingElements = tail;
    } else {
        break;
    }
}
 

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

Обратите также внимание, что представленные здесь детали соответствуют очевидной идее вашего исходного примера: они соответствуют первому появлению startTag с первым появлением после этого endTag . Это может быть не то, что вы на самом деле хотите, если вам нужно учитывать вложенность тегов. Например, результат с startTag = "<text>"; endTag = "</text>"; был бы [</p>, </text>] . Вы все еще можете использовать subList в таком случае, но вам нужно быть умнее в определении границ диапазона.

Комментарии:

1. Спасибо за подробный ответ и лучшее понимание того, как лучше решить проблему.

Ответ №2:

Используйте итератор (то есть безопасное изменение параллелизма) и удаляйте элементы вместо добавления в список удаления

    boolean delete = false;
   Iterator it = elements.iterator();
   while(it.hasNext()) {
        String element it.next();
        if(delete)
            it.remove();

        if(element.startsWith(startTag)) {
            delete = true;
            it.remove();
        }
        if(element.endsWith(endTag)) {
            delete = false;
            it.remove();
        }
    }
}
 

Комментарии:

1. Потенциальная проблема с этим подходом: если startTag появляется в списке, но endTag не появляется, то весь хвост списка удаляется, даже если он не ограничен парой (startTag, endTag).