Регулярное выражение: как заменить строку на n вхождений подстроки - PullRequest
0 голосов
/ 06 сентября 2018

В качестве предпосылки у меня есть текст HTML с некоторыми элементами <ol>. Они имеют атрибут start, но используемый мной фреймворк не способен их интерпретировать во время преобразования PDF. Итак, хитрость, которую я пытаюсь применить, заключается в добавлении нескольких невидимых <li> элементов в начале.

В качестве примера предположим, что этот входной текст:

<ol start="3">
   <li>Element 1</li>
   <li>Element 2</li>
   <li>Element 3</li>
</ol>

Я хочу получить такой результат:

<ol>
   <li style="visibility:hidden"></li>
   <li style="visibility:hidden"></li>
   <li>Element 1</li>
   <li>Element 2</li>
   <li>Element 3</li>
</ol>

Итак, добавление n-1 невидимых элементов в упорядоченный список. Но я не могу сделать это из Java в обобщенном виде.

Предполагая точный случай в примере, я мог бы сделать это (используя replace, поэтому, если честно, без регулярных выражений):

htmlString = htmlString.replace("<ol start=\"3\">",
            "<ol><li style=\"visibility:hidden\"></li><li style=\"visibility:hidden\"></li>");

Но, очевидно, это относится только к случаю с «start = 3». Я знаю, что могу использовать группы для извлечения «3», но как я могу использовать его как «переменную» для указания строки <li style=\"visibility:hidden\"></li> n-1 количество раз? Спасибо за понимание.

Ответы [ 5 ]

0 голосов
/ 06 сентября 2018

Вы можете попробовать это.

String input="<ol    start=\"6\">"+
   "<li>Element 1</li>"+
   "<li>Element 2</li>"+
   "<li>Element 3</li>"+
   "<li>Element 4</li>"+
   "<li>Element 5</li>"+
   "<li>Element6</li>"+
"</ol>";

 Matcher match= Pattern.compile("<ol .*start.*=.*\\\"(.*)\\\"\\s*>(.*)(</ol>)").matcher(input);
    String resultString ="";
    if(match.find()){
    resultString =match.replaceAll("<ol>"+new String(new char[Integer.valueOf(match.group(1))-1]).replace("\0", "\n\t<li style=\"visibility:hidden\" />")+"$2$3");  

}
0 голосов
/ 06 сентября 2018

Пожалуйста, используйте java Matcher и Pattern для подсчета появления тега li и используйте StringBuilder insert способ вставки невидимых элементов.

Matcher m = Pattern.compile("<li>").matcher(s);
        while(m.find()){
           ++count;
        }
0 голосов
/ 06 сентября 2018

Начиная с Java 9, существует метод Matcher.replaceAll, принимающий функцию обратного вызова в качестве параметра:

String text = "<ol start=\"3\">\n\t<li>Element 1</li>\n\t<li>Element 2</li>\n\t<li>Element 3</li>\n</ol>";

String result = Pattern
        .compile("<ol start=\"(\\d)\">")
        .matcher(text)
        .replaceAll(m -> "<ol>" + repeat("\n\t<li style=\"visibility:hidden\" />", 
                                         Integer.parseInt(m.group(1))-1));      

К repeat строке, которую вы можете взять из здесь или использовать цикл.

public static String repeat(String s, int n) {
    return new String(new char[n]).replace("\0", s);
}

После этого result будет:

<ol>
    <li style="visibility:hidden" />
    <li style="visibility:hidden" />
    <li>Element 1</li>
    <li>Element 2</li>
    <li>Element 3</li>
</ol>   

Если вы застряли на более старой версии Java, вы все равно можете выполнить поиск и замену в два этапа.

Matcher m = Pattern.compile("<ol start=\"(\\d)\">").matcher(text);
while (m.find()) {
    int n = Integer.parseInt(m.group(1));
    text = text.replace("<ol start=\"" + n + "\">", 
            "<ol>" + repeat("\n\t<li style=\"visibility:hidden\" />", n-1));
}

Обновление от Andrea * ー テ ィ ー オ ー:

Я изменил (отличное) решение, приведенное выше, для включения также <ol>, которые имеют несколько атрибутов, чтобы их тег не заканчивался на start (например, <ol> с буквами, такими как <ol start="4" style="list-style-type: upper-alpha;">). При этом используется replaceAll для работы с регулярным выражением в целом.

//Take something that starts with "<ol start=", ends with ">", and has a number in between
Matcher m = Pattern.compile("<ol start=\"(\\d)\"(.*?)>").matcher(htmlString);
while (m.find()) {
    int n = Integer.parseInt(m.group(1));
    htmlString = htmlString.replaceAll("(<ol start=\"" + n + "\")(.*?)(>)",
            "<ol $2>" + StringUtils.repeat("\n\t<li style=\"visibility:hidden\" />", n - 1));
}
0 голосов
/ 06 сентября 2018

Используя Jsoup, вы можете написать что-то вроде:

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

class JsoupTest {
    public static void main(String[] args){
        String html = "<ol start=\"3\">\n" +
                        "   <li>Element 1</li>\n" +
                        "   <li>Element 2</li>\n" +
                        "   <li>Element 3</li>\n" +
                        "</ol>"
                + "<p>some other html elements</p>"
                + "<ol start=\"5\">\n" +
                        "   <li>Element 1</li>\n" +
                        "   <li>Element 2</li>\n" +
                        "   <li>Element 3</li>\n" +
                        "   <li>Element 4</li>\n" +
                        "   <li>Element 5</li>\n" +
                        "</ol>";

        Document doc = Jsoup.parse(html);
        Elements ols = doc.select("ol");
        for(Element ol :ols){
            int start = Integer.parseInt(ol.attr("start"));
            for(int i=0; i<start-1; i++){
                ol.prependElement("li").attr("style", "visibility:hidden");
            }  
            ol.attributes().remove("start");
            System.out.println(ol);
        }
    }
}
0 голосов
/ 06 сентября 2018

Вы не можете сделать это с помощью регулярных выражений, или даже если вы найдете какой-нибудь хак для этого, это будет неоптимальным решением.

Правильный способ сделать это - использовать библиотеку HTML для разбора (например, Jsoup ), а затем добавить теги <li> в качестве дочерних элементов к <ol>, в частности, используя Element # метод prepend . (С помощью Jsoup вы также можете прочитать значение атрибута start, чтобы вычислить, сколько элементов добавить)

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