Как обнаружить наличие URL в строке - PullRequest
26 голосов
/ 13 ноября 2008

У меня есть входная строка, скажем Please go to http://stackoverflow.com. Часть URL строки String обнаружена, и многие браузеры / IDE / приложения автоматически добавляют привязку <a href=""></a>. Так становится Please go to <a href='http://stackoverflow.com'>http://stackoverflow.com</a>.

Мне нужно сделать то же самое с помощью Java.

Ответы [ 12 ]

56 голосов
/ 13 ноября 2008

Используйте для этого java.net.URL !!

Эй, почему бы не использовать базовый класс в java для этого "java.net.URL" и позволить ему проверить URL.

Хотя следующий код нарушает золотой принцип «Использовать исключение только для исключительных условий», мне не имеет смысла пытаться заново изобрести колесо для чего-то очень зрелого на Java-платформе.

Вот код:

import java.net.URL;
import java.net.MalformedURLException;

// Replaces URLs with html hrefs codes
public class URLInString {
    public static void main(String[] args) {
        String s = args[0];
        // separate input by spaces ( URLs don't have spaces )
        String [] parts = s.split("\\s+");

        // Attempt to convert each item into an URL.   
        for( String item : parts ) try {
            URL url = new URL(item);
            // If possible then replace with anchor...
            System.out.print("<a href=\"" + url + "\">"+ url + "</a> " );    
        } catch (MalformedURLException e) {
            // If there was an URL that was not it!...
            System.out.print( item + " " );
        }

        System.out.println();
    }
}

Использование следующего ввода:

"Please go to http://stackoverflow.com and then mailto:oscarreyes@wordpress.com to download a file from    ftp://user:pass@someserver/someFile.txt"

Создает следующий вывод:

Please go to <a href="http://stackoverflow.com">http://stackoverflow.com</a> and then <a href="mailto:oscarreyes@wordpress.com">mailto:oscarreyes@wordpress.com</a> to download a file from    <a href="ftp://user:pass@someserver/someFile.txt">ftp://user:pass@someserver/someFile.txt</a>

Конечно, разные протоколы могут обрабатываться по-разному. Вы можете получить всю информацию с помощью получателей класса URL, например

 url.getProtocol();

Или остальные атрибуты: спецификация, порт, файл, запрос, ссылка и т. Д. И т. Д.

http://java.sun.com/javase/6/docs/api/java/net/URL.html

Обрабатывает все протоколы (по крайней мере, все те, которые знает платформа java) и в качестве дополнительного преимущества, если есть какой-либо URL, который в настоящий момент не распознается java и в конечном итоге включается в класс URL (путем обновления библиотеки) получу прозрачно!

14 голосов
/ 13 ноября 2008

Хотя это не специфично для Java, Джефф Этвуд недавно опубликовал статью о подводных камнях, с которыми вы можете столкнуться при попытке найти и сопоставить URL-адреса в произвольном тексте:

Проблема с URL

Это дает хорошее регулярное выражение, которое можно использовать вместе с фрагментом кода, который вам нужно использовать для правильной (более или менее) обработки паренов.

Регулярное выражение:

\(?\bhttp://[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|]

Чистка парен:

if (s.StartsWith("(") && s.EndsWith(")"))
{
    return s.Substring(1, s.Length - 2);
}
4 голосов
/ 13 ноября 2008

Вы можете сделать что-то вроде этого (настроить регулярное выражение в соответствии со своими потребностями):

String originalString = "Please go to http://www.stackoverflow.com";
String newString = originalString.replaceAll("http://.+?(com|net|org)/{0,1}", "<a href=\"$0\">$0</a>");
2 голосов
/ 07 марта 2012

Следующий код вносит эти изменения в «подход Этвуда»:

  1. Обнаруживает https в дополнение к http (добавление других схем тривиально)
  2. Используется флаг CASE_INSENSTIVE, поскольку HtTpS: // является действительным.
  3. Соответствующие наборы скобок отслаиваются (их можно вкладывать в любой уровень). Кроме того, любые оставшиеся несопоставленные левые скобки раздетые, но завершающие правые скобки остаются нетронутыми (для уважения URL в стиле википедии)
  4. URL-адрес HTML-кодируется в тексте ссылки.
  5. Целевой атрибут передается через параметр метода. Другие атрибуты могут быть добавлены по желанию.
  6. Он не использует \ b для определения разрыва слова перед соответствием URL. URL-адреса могут начинаться с левой круглой скобки или http [s]: // без каких-либо других требований.

Примечания:

  • Apache Commons Lang StringUtils используются в приведенном ниже коде
  • Вызов HtmlUtil.encode () ниже - это утилита, которая в конечном итоге вызывает некоторый код томагавка для HTML-кодирования текста ссылки, но подойдет любая подобная утилита.
  • См. Комментарий к методу для использования в JSF или других средах, где по умолчанию выводится HTML-кодирование.

Это было написано в ответ на требования нашего клиента, и мы считаем, что оно представляет собой разумный компромисс между допустимыми символами из RFC и обычным использованием. Это предлагается здесь в надежде, что это будет полезно для других.

Возможно дальнейшее расширение, которое позволит вводить любые символы Юникода (т. Е. Не экранировать с помощью% XX (двузначный шестнадцатеричный код) и гиперссылки, но для этого потребуется принять все буквы Юникода плюс ограниченную пунктуацию, а затем разделить на "" допустимые разделители (например,.,%, |, # и т. д.), URL-кодирование каждой части, а затем склейка обратно. Например, http://en.wikipedia.org/wiki/Björn_Andrésen (который не обнаруживает генератор переполнения стека) будет "http://en.wikipedia.org/wiki/Bj%C3%B6rn_Andr%C3%A9sen" в href, но будет содержать Björn_Andrésen в связанном тексте на странице.

<code>// NOTES:   1) \w includes 0-9, a-z, A-Z, _
//          2) The leading '-' is the '-' character. It must go first in character class expression
private static final String VALID_CHARS = "-\\w+&@#/%=~()|";
private static final String VALID_NON_TERMINAL = "?!:,.;";

// Notes on the expression:
//  1) Any number of leading '(' (left parenthesis) accepted.  Will be dealt with.  
//  2) s? ==> the s is optional so either [http, https] accepted as scheme
//  3) All valid chars accepted and then one or more
//  4) Case insensitive so that the scheme can be hTtPs (for example) if desired
private static final Pattern URI_FINDER_PATTERN = Pattern.compile("\\(*https?://["+ VALID_CHARS + VALID_NON_TERMINAL + "]*[" +VALID_CHARS + "]", Pattern.CASE_INSENSITIVE );

/**
 * <p>
 * Finds all "URL"s in the given _rawText, wraps them in 
 * HTML link tags and returns the result (with the rest of the text
 * html encoded).
 * </p>
 * <p>
 * We employ the procedure described at:
 * http://www.codinghorror.com/blog/2008/10/the-problem-with-urls.html
 * which is a <b>must-read</b>.
 * </p>
 * Basically, we allow any number of left parenthesis (which will get stripped away)
 * followed by http:// or https://.  Then any number of permitted URL characters
 * (based on http://www.ietf.org/rfc/rfc1738.txt) followed by a single character
 * of that set (basically, those minus typical punctuation).  We remove all sets of 
 * matching left & right parentheses which surround the URL.
 *</p>
 * <p>
 * This method *must* be called from a tag/component which will NOT
 * end up escaping the output.  For example:
 * <PRE>
 * <h:outputText ... escape="false" value="#{core:hyperlinkText(textThatMayHaveURLs, '_blank')}"/>
 * 
* *

* Причина: мы добавляем &lt;a href="..."&gt; тегов к выводу * и * * кодирование остальной части строки. Таким образом, кодирование outupt приведет к * двойное кодирование данных, которые уже были закодированы - и кодирование a href * (что сделает его бесполезным). *

*

* * @param _rawText - если null, возвращает "" (пустая строка). * @param _target - если не null или "", добавляет цель, присвоенную сгенерированной ссылке, используя _target в качестве значения атрибута. * / public static final String hyperlinkText (final String _rawText, final String _target) { String returnValue = null; if (! StringUtils.isBlank (_rawText)) { final Matcher matcher = URI_FINDER_PATTERN.matcher (_rawText); if (matcher.find ()) { final int originalLength = _rawText.length (); final String targetText = (StringUtils.isBlank (_target))? "": "target = \" "+ _target.trim () +" \ ""; final int targetLength = targetText.length (); // Подсчитано 15 символов помимо цели + 2 URL (максимум, если вся строка является URL) // Грубое предположение, но мы не должны расширять Builder слишком много раз. final StringBuilder returnBuffer = new StringBuilder (originalLength * 2 + targetLength + 15); int currentStart; int currentEnd; int lastEnd = 0; Строка currentURL; делать { currentStart = matcher.start (); currentEnd = matcher.end (); currentURL = matcher.group (); // Корректируем для URL-адресов, обернутых в () 's ... переместить маркеры начала / конца // и подстрока _rawText для нового значения URL. while (currentURL.startsWith ("(") && currentURL.endsWith (")")) { currentStart = currentStart + 1; currentEnd = currentEnd - 1;currentURL = _rawText.substring (currentStart, currentEnd); } while (currentURL.startsWith ("(")) { currentStart = currentStart + 1; currentURL = _rawText.substring (currentStart, currentEnd); } // Текст с последнего совпадения returnBuffer.append (HtmlUtil.encode (_rawText.substring (lastEnd, currentStart)))); // Обернуть совпавший URL returnBuffer.append ("" + currentURL + ""); lastEnd = currentEnd; } while (matcher.find ()); if (lastEnd

1 голос
/ 14 июня 2015

Я сделал небольшую библиотеку, которая делает именно это:

https://github.com/robinst/autolink-java

Некоторые хитрые примеры и ссылки, которые он обнаруживает:

0 голосов
/ 27 марта 2017

Предлагая более удобный способ сделать это в 2017 году:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:autoLink="web"
    android:linksClickable="true"/>

или android:autoLink="all" для всех видов ссылок.

0 голосов
/ 03 августа 2016

Существует очень хорошая структура JavaScript, которая отображает ссылки прямо в браузере: https://github.com/gregjacobs/Autolinker.js

Поддерживаются: html, электронная почта, (только для нас) номер телефона, твиттер и хэштеги.

Он также отображает ссылки без: http://

0 голосов
/ 08 сентября 2012

Я написал свой собственный URI / URL-экстрактор и подумал, что кто-то может найти его полезным, учитывая, что ИМХО лучше других ответов, потому что:

  • Его поток основан и может использоваться для больших документов
  • Возможность расширения для решения всех видов проблем "Atwood Paren" через цепочку стратегий.

Так как код довольно длинный для поста (хотя только один файл Java), я поместил его на gist github .

Вот подпись одного из основных методов для его вызова, чтобы показать, как это указано выше:

public static Iterator<ExtractedURI> extractURIs(
    final Reader reader,
    final Iterable<ToURIStrategy> strategies,
    String ... schemes);

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

public static List<ToURIStrategy> DEFAULT_STRATEGY_CHAIN = ImmutableList.of(
    new RemoveSurroundsWithToURIStrategy("'"),
    new RemoveSurroundsWithToURIStrategy("\""),
    new RemoveSurroundsWithToURIStrategy("(", ")"),
    new RemoveEndsWithToURIStrategy("."),
    DEFAULT_STRATEGY,
    REMOVE_LAST_STRATEGY);

Наслаждайтесь!

0 голосов
/ 09 июля 2012

Чтобы определить URL, вам просто нужно:

if (yourtextview.getText().toString().contains("www") || yourtextview.getText().toString().contains("http://"){ your code here if contains URL;}
0 голосов
/ 19 августа 2011

Хорошим уточнением ответа Филио будет: msg.replaceAll("(?:https?|ftps?)://[\w/%.-][/\??\w=?\w?/%.-]?[/\?&\w=?\w?/%.-]*", "$0");

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