Как преобразовать не кликабельные URL-адреса в виде обычного текста в ссылки в HTML источнике - PullRequest
0 голосов
/ 09 мая 2020

Я хочу обнаружить URL-адреса и сделать их ссылочными в коде HTML. Я искал переполнение стека, но многие ответы касаются обнаружения и преобразования ссылок в текстовых строках. Когда я это сделаю, код html будет недействителен; ie. исходники img изменятся, et c.

PS: Закройте голосующие: пожалуйста, прочтите вопрос внимательно! Это не дубликат.

Например; строка 1 должна быть преобразована, а строки 2 и 3 - нет.

<!-- Sample html source -->
<div>
   Line 1 : https://www.google.com/
   Line 2 : <a href="https://www.google.com/">https://www.google.com/</a>
   Line 3: <img src="http://a-domain.com/lovely-image.jpg">
</div>

Мне нужно:

  1. Найти любой URL-адрес в html часть тела

  2. Проверить, кликабельна она или нет: если она не заключена в символы 'a', 'img', '! -', et c ..

  3. Если не сделать его кликабельным: Оберните 'a'

Как я могу это сделать? Все версии C# и JS мне подходят.

ПОСЛЕДНЕЕ ОБНОВЛЕНИЕ Изменение цели сборки проекта с 4.7.2 на 4.5 и обратно на 4.7.2 устранило «ошибку».

ОБНОВЛЕНИЕ: Это мое решение с помощью @jira. Проблема в том, что узлы вообще не изменятся. Я имею в виду, что рекурсивная функция выполняет свою работу, заменяет ссылки, говорит отладка, однако документ html не обновляется вообще. Любая модификация внутри функции не действует вне функции, я не знаю почему, InnerText изменяется - внутренний Html не меняется

var htmlVersion = "<html><head></head><body>\r\n"
   + "Some text\r\n"
   + "<div>http://google.com</div>\r\n"
   + " Then later more text: http://500px.com\r\n"
   + "<div>Sub <span>abc</span> Back text</div>\r\n"
   + "And the final text"
   + "</body></html>";

var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(htmlVersion);

// Linkify body
var modified = false;
var bodyNode = doc.DocumentNode.SelectSingleNode("//body"); 
var before = bodyNode.InnerHtml;
bodyNode = Linkify(bodyNode);
modified = modified || bodyNode.InnerHtml != before;
// modified is false !!!

Рекурсивная Linkify функция:

HtmlAgilityPack.HtmlNode Linkify(HtmlAgilityPack.HtmlNode node)
{
    if (node.Name == "a") // It's already a link
    {
        return node;
    }

    if (node.Name == "#text") // Do replacement here
    {

        // Create links
        // https://stackoverflow.com/a/4750468/627193
        node.InnerHtml = Regex.Replace(node.InnerHtml,
            @"((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?)",
            "<a target='_blank' href='$1'>$1</a>");

    }

    for (int i = 0; i < node.ChildNodes.Count; i++) // Go for child nodes
    {
        node.ChildNodes[i] = Linkify(node.ChildNodes[i]);
    }
    return node;
}

Ответы [ 2 ]

3 голосов
/ 09 мая 2020

Используйте парсер html, например HtmlAgility Pack . Выберите только текстовые узлы, а затем ищите в них ссылки. Таким образом, вы не будете касаться существующих ссылок. В зависимости от того, насколько точным вам нужно быть, вы можете использовать регулярное выражение.

Например

var doc = new HtmlDocument();
doc.LoadHtml(html);
Regex r = new Regex(@"(https?://[^\s]+)");
var textNodes = doc.DocumentNode.SelectNodes("//text()");

foreach (var textNode in textNodes) {
    var text = textNode.GetDirectInnerText();
    var withLinks = r.Replace(text, "<a href=\"$1\">$1</a>");
    textNode.InnerHtml = withLinks;
}

Fiddle

Регулярное выражение для правильной проверки ссылок может быть довольно сложным. Проверьте другие ответы здесь, на SO.

0 голосов
/ 10 мая 2020

После изменения цели сборки проекта с 4.7.2 на 4.5 и go обратно на 4.7.2 снова исправлена ​​«ошибка».

Вот рабочий код:

var htmlVersion = "<html><head></head><body>\r\n"
   + "Some text\r\n"
   + "<div>http://google.com</div>\r\n"
   + " Then later more text: http://500px.com\r\n"
   + "<div>Sub <span>abc</span> Back text</div>\r\n"
   + "And the final text"
   + "</body></html>";

var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(htmlVersion);

// Linkify body
var modified = false;
var bodyNode = doc.DocumentNode.SelectSingleNode("//body"); 
var before = bodyNode.InnerHtml;
bodyNode = Linkify(bodyNode);
modified = modified || bodyNode.InnerHtml != before;

Рекурсивная функция Linkify:

HtmlAgilityPack.HtmlNode Linkify(HtmlAgilityPack.HtmlNode node)
{
    if (node == null || node.Name == "a") // It's already a link
    {
        return node;
    }

    if (node.Name == "#text") // Do replacement here
    {

        // Create links
        // https://stackoverflow.com/a/4750468/627193
        node.InnerHtml = Regex.Replace(node.InnerHtml,
            @"((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?)",
            "<a target='_blank' href='$1'>$1</a>");

    }

    for (int i = 0; i < node.ChildNodes.Count; i++) // Go for child nodes
    {
        node.ChildNodes[i] = Linkify(node.ChildNodes[i]);
    }
    return node;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...