Java regex для извлечения ссылки из текста

У меня есть вход String как:

String text = "Some content which contains link as <A HREF=\"/relative-path/fruit.cgi?param1=abc&param2=xyz\">URL Label</A> and some text after it";

Я хочу преобразовать этот текст в:

Some content which contains link as http://www.google.com/relative-path/fruit.cgi?param1=abc&param2=xyz&myParam=pqr (URL Label) and some text after it

Так вот:

1) Я хочу заменить тег ссылки простой ссылкой. Если тег содержит метку, он должен быть заключен в фигурные скобки после URL-адреса.

2) Если URL-адрес относительный, я хочу поставить префикс базового URL-адреса (http://www.google.com).

3) Я хочу добавить параметр к URL-адресу. (& myParam = pqr)

У меня проблемы с получением тега с URL и меткой и его заменой.

Я написал что-то вроде:

public static void main(String[] args) {
    String text = "String text = "Some content which contains link as <A HREF=\"/relative-path/fruit.cgi?param1=abc&param2=xyz\">URL Label</A> and some text after it";";
    text = text.replaceAll("&lt;", "<");
    text = text.replaceAll("&gt;", ">");
    text = text.replaceAll("&amp;", "&");

    // this is not working
    Pattern p = Pattern.compile("href=\"(.*?)\"");
    Matcher m = p.matcher(text);
    String url = null;
    if (m.find()) {
        url = m.group(1);

    }
}

// helper method to append new query params once I have the url
public static URI appendQueryParams(String uriToUpdate, String queryParamsToAppend) throws URISyntaxException {
    URI oldUri = new URI(uriToUpdate);
    String newQueryParams = oldUri.getQuery();
    if (newQueryParams == null) {
        newQueryParams = queryParamsToAppend;
    } else {
        newQueryParams += "&" + queryParamsToAppend;  
    }
    URI newUri = new URI(oldUri.getScheme(), oldUri.getAuthority(),
            oldUri.getPath(), newQueryParams, oldUri.getFragment());
    return newUri;
}

Edit1:

Pattern p = Pattern.compile("HREF=\"(.*?)\"");

Это работает. Но тогда я хочу, чтобы он не зависел от капитализации. Href, HRef, href, hrEF и т.д. - все должно работать.

Кроме того, что делать, если в моем тексте несколько URL-адресов.

Edit2:

Некоторый прогресс.

Pattern p = Pattern.compile("href=\"(.*?)\"");
Matcher m = p.matcher(text);
String url = null;
while (m.find()) {
  url = m.group(1);
  System.out.println(url);
}

Это обрабатывает случай нескольких URL-адресов.

Последняя нерешенная проблема: как получить метку и заменить теги href в исходном тексте на URL и метку.

Edit3:

Под несколькими вариантами URL-адресов я подразумеваю, что в данном тексте присутствует несколько URL-адресов.

String text = "Some content which contains link as &lt;A HREF=\"/relative-path/fruit.cgi?param1=abc&amp;param2=xyz\"&gt;URL Label&lt;/A&gt; and some text after it and another link &lt;A HREF=\"/relative-path/vegetables.cgi?param1=abc&amp;param2=xyz\"&gt;URL2 Label&lt;/A&gt; and some more text";

Pattern p = Pattern.compile("href=\"(.*?)\"", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(text);
String url = null;
while (m.find()) {
 url = m.group(1); // this variable should contain the link URL
 url = appendBaseURI(url);
 url = appendQueryParams(url, "license=ABCXYZ");
 System.out.println(url);
}

Начните с преобразования HTML-сущностей с помощью: import org.apache.commons.lang.StringEscapeUtils; String entities_decode = StringEscapeUtils.unescapeHtml(text );

Pedro Lobito 22.11.2018 04:23
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
296
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

// this is not working

Потому что ваше регулярное выражение чувствительно к регистру.

Пытаться:-

Pattern p = Pattern.compile("href=\"(.*?)\"", Pattern.CASE_INSENSITIVE);

Редактировать1:
Чтобы получить этикетку, используйте Pattern.compile("(?<=>).*?(?=</a>)", Pattern.CASE_INSENSITIVE) и m.group(0).

Редактировать2:
Чтобы заменить тег (включая метку) последней строкой, используйте: -

text.replaceAll("(?i)<a href=\"(.*?)</a>", "new substring here")

Спасибо. Только что узнал об этом. Отредактировали вопрос для того же.

Vicky 22.11.2018 03:47

Так это не отвечает на ваш вопрос? Если нет, то какова следующая проблема?

Kartik 22.11.2018 03:48

На самом деле 3 проблемы: 1) как мне обрабатывать несколько случаев URL-адресов, 2) Как мне получить метку, 3) После того, как у меня есть URL-адреса с префиксом базового URL-адреса и прикрепленным параметром, как мне заменить их в исходном тексте.

Vicky 22.11.2018 03:50

1) что вы имеете в виду под несколько вариантов URL? Вы можете дополнить свой вопрос примером? 2) Обновлен ответ для метки 3) точно так же, как вы заменили раньше, сделайте обратное и, о, используйте replace вместо replaceAll

Kartik 22.11.2018 04:00

отредактировал. Я не понял заменяемую часть. Что значит "как будто вы заменили раньше"?

Vicky 22.11.2018 04:05

см. мою вторую правку, я надеюсь, что на все ваши вопросы сейчас дан ответ

Kartik 22.11.2018 04:07

Шаблон для получения меток не работает в случае текста с несколькими URL-адресами. :( Ненавижу регулярное выражение! Не знаю, когда я его освоу.

Vicky 22.11.2018 04:13

Вы можете использовать m.group(0), m.group(1) и т. д., Чтобы получить все группы, запустить replaceAll из моего edit2 и затем объединить их. Или разделите текст ранее в своей программе, а затем запустите replaceAll в цикле. Я сделал сложную часть, связанную с регулярным выражением, теперь вы должны завершить ее.

Kartik 22.11.2018 04:16

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

Vicky 22.11.2018 04:20

@Nik опубликовал полный код в качестве другого ответа с примером нескольких URL-адресов

Kartik 22.11.2018 06:48

Вы можете использовать текст общего доступа apacheStringEscapeUtils для декодирования html-сущностей, а затем replaceAll, то есть:

import org.apache.commons.text.StringEscapeUtils;

String text = "Some content which contains link as &lt;A HREF=\"/relative-path/fruit.cgi?param1=abc&amp;param2=xyz\"&gt;URL Label&lt;/A&gt; and some text after it";
String output = StringEscapeUtils.unescapeHtml4(text).replaceAll("([^<]+).+\"(.*?)\">(.*?)<[^>]+>(.*)", "$1https://google.com$2&your_param ($3)$4");
System.out.print(output);
// Some content which contains link as https://google.com/relative-path/fruit.cgi?param1=abc&param2=xyz&your_param (URL Label) and some text after it

Демо:

  1. jdoodle
  2. Regex Объяснение

Это действительно изящно и идеально подходит для моего необходимого решения, если оно может обрабатывать сценарии с несколькими URL-адресами. Кроме того, я предполагаю, что ваше решение предполагает, что URL-адрес всегда должен иметь префикс google.com, что не так, как упоминалось в пункте (2) моего вопроса. Я добавлю базовый URI, только если он отсутствует. Спасибо за ответ! постараюсь расширить его.

Vicky 22.11.2018 06:00

сделайте baseurl также динамичным.

Pedro Lobito 22.11.2018 16:07
Ответ принят как подходящий
public static void main(String args[]) {
    String text = "Some content which contains link as &lt;A HREF=\"/relative-path/fruit.cgi?param1=abc&amp;param2=xyz\"&gt;URL Label&lt;/A&gt; and some text after it and another link &lt;A HREF=\"/relative-path/vegetables.cgi?param1=abc&amp;param2=xyz\"&gt;URL2 Label&lt;/A&gt; and some more text";
    text = StringEscapeUtils.unescapeHtml4(text);
    Pattern p = Pattern.compile("<a href=\"(.*?)\">(.*?)</a>", Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(text);
    while (m.find()) {
        text = text.replace(m.group(0), cleanUrlPart(m.group(1), m.group(2)));
    }
    System.out.println(text);
}

private static String cleanUrlPart(String url, String label) {
    if (!url.startsWith("http") && !url.startsWith("www")) {
        if (url.startsWith("/")) {
            url = "http://www.google.com" + url;
        } else {
            url = "http://www.google.com/" + url;
        }
    }
    url = appendQueryParams(url, "myParam=pqr").toString();
    if (label != null && !label.isEmpty()) url += " (" + label + ")";
    return url;
}

Вывод

Some content which contains link as http://www.google.com/relative-path/fruit.cgi?param1=abc&param2=xyz&myParam=pqr (URL Label) and some text after it and another link http://www.google.com/relative-path/vegetables.cgi?param1=abc&param2=xyz&myParam=pqr (URL2 Label) and some more text

о ... не видел этого и отправил свой ответ ... Я просто пытаюсь заменить деталь ... сначала попробую сделать свой ответ ... иначе попробую ваш ... спасибо!

Vicky 22.11.2018 07:10

Почти готово:

public static void main(String[] args) throws URISyntaxException {
        String text = "Some content which contains link as &lt;A HREF=\"/relative-path/fruit.cgi?param1=abc&amp;param2=xyz\"&gt;URL Label&lt;/A&gt; and some text after it and another link &lt;A HREF=\"/relative-path/vegetables.cgi?param1=abc&amp;param2=xyz\"&gt;URL2 Label&lt;/A&gt; and some more text";
        text = StringEscapeUtils.unescapeHtml4(text);
        System.out.println(text);
        System.out.println("**************************************");
        Pattern patternTag = Pattern.compile("<a([^>]+)>(.+?)</a>", Pattern.CASE_INSENSITIVE);
        Pattern patternLink = Pattern.compile("href=\"(.*?)\"", Pattern.CASE_INSENSITIVE);
        Matcher matcherTag = patternTag.matcher(text);

        while (matcherTag.find()) {
            String href = matcherTag.group(1); // href
            String linkText = matcherTag.group(2); // link text
            System.out.println("Href: " + href);
            System.out.println("Label: " + linkText);
            Matcher matcherLink = patternLink.matcher(href);
            String finalText = null;
            while (matcherLink.find()) {
                String link = matcherLink.group(1);
                System.out.println("Link: " + link);
                finalText = getFinalText(link, linkText);
                break;
            }
            System.out.println("***************************************");
            // replacing logic goes here
        }
        System.out.println(text);
    }

    public static String getFinalText(String link, String label) throws URISyntaxException {
        link = appendBaseURI(link);
        link = appendQueryParams(link, "myParam=ABCXYZ");
        return link + " (" + label + ")";
    }

    public static String appendQueryParams(String uriToUpdate, String queryParamsToAppend) throws URISyntaxException {
        URI oldUri = new URI(uriToUpdate);
        String newQueryParams = oldUri.getQuery();
        if (newQueryParams == null) {
            newQueryParams = queryParamsToAppend;
        } else {
            newQueryParams += "&" + queryParamsToAppend;  
        }
        URI newUri = new URI(oldUri.getScheme(), oldUri.getAuthority(),
                oldUri.getPath(), newQueryParams, oldUri.getFragment());
        return newUri.toString();
    }

    public static String appendBaseURI(String url) {
        String baseURI = "http://www.google.com/";
        if (url.startsWith("/")) {
            url = url.substring(1, url.length());
        }
        if (url.startsWith(baseURI)) {
            return url;
        } else {
            return baseURI + url;
        }
    }

Другие вопросы по теме