Подтвердить что ты не робот

Как определить наличие URL-адреса в строке

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

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

4b9b3361

Ответ 1

Используйте 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:[email protected] to download a file from    ftp://user:[email protected]/someFile.txt"

Производит следующий вывод:

Please go to <a href="http://stackoverflow.com">http://stackoverflow.com</a> and then <a href="mailto:[email protected]">mailto:[email protected]</a> to download a file from    <a href="ftp://user:[email protected]/someFile.txt">ftp://user:[email protected]/someFile.txt</a>

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

 url.getProtocol();

Или остальные атрибуты: spec, порт, файл, запрос, ref и т.д. и т.д.

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

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

Ответ 2

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

Проблема с URL-адресами

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

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

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

Очистка пар:

if (s.StartsWith("(") && s.EndsWith(")"))
{
    return s.Substring(1, s.Length - 2);
}

Ответ 3

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

String originalString = "Please go to http://www.stackoverflow.com";
String newString = originalString.replaceAll("http://.+?(com|net|org)/{0,1}", "<a href=\"$0\">$0</a>");

Ответ 4

Следующий код вносит эти изменения в "Atwood Approach":

  • Обнаруживает https в дополнение к http (добавление других схем тривиально)
  • Флаг CASE_INSENSTIVE используется, поскольку HtTpS://действителен.
  • Соответствующие наборы скобок отслаиваются (они могут быть вложены в любой уровень). Кроме того, любые оставшиеся несогласованные левые круглые скобки лишенные, но конечные правые круглые скобки остаются нетронутыми (уважать URL-адреса в стиле википедии)
  • URL-адрес HTML кодируется в тексте ссылки.
  • Атрибут target передается через параметр метода. Другие атрибуты могут быть добавлены по желанию.
  • Он не использует \b для определения разрыва слова перед сопоставлением URL-адреса. URL-адреса могут начинаться с левой скобки или http [s]://без других требований.

Примечания:

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

Это было написано в ответ на наши требования клиентов, и мы считаем, что он представляет собой разумный компромисс между допустимыми символами 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 в связанный текст на странице.

// 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')}"/>
 * </pre>
 * </p>
 * <p>
 * Reason: we are adding <code>&lt;a href="..."&gt;</code> tags to the output *and*
 * encoding the rest of the string.  So, encoding the outupt will result in
 * double-encoding data which was already encoded - and encoding the <code>a href</code>
 * (which will render it useless).
 * </p>
 * <p>
 * 
 * @param   _rawText  - if <code>null</code>, returns <code>""</code> (empty string).
 * @param   _target   - if not <code>null</code> or <code>""</code>, adds a target attributed to the generated link, using _target as the attribute value.
 */
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();

            // Counted 15 characters aside from the target + 2 of the URL (max if the whole string is URL)
            // Rough guess, but should keep us from expanding the Builder too many times.
            final StringBuilder returnBuffer = new StringBuilder( originalLength * 2 + targetLength + 15 );

            int currentStart;
            int currentEnd;
            int lastEnd     = 0;

            String currentURL;

            do {
                currentStart = matcher.start();
                currentEnd = matcher.end();
                currentURL = matcher.group();

                // Adjust for URLs wrapped in () ... move start/end markers
                //      and substring the _rawText for new URL value.
                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 );
                }

                // Text since last match
                returnBuffer.append( HtmlUtil.encode( _rawText.substring( lastEnd, currentStart ) ) );

                // Wrap matched URL
                returnBuffer.append( "<a href=\"" + currentURL + "\"" + targetText + ">" + currentURL + "</a>" );

                lastEnd = currentEnd;

            } while ( matcher.find() );

            if ( lastEnd < originalLength ) {
                returnBuffer.append( HtmlUtil.encode( _rawText.substring( lastEnd ) ) );
            }

            returnValue = returnBuffer.toString();
        }
    } 

    if ( returnValue == null ) {
        returnValue = HtmlUtil.encode( _rawText );
    }

    return returnValue;

}

Ответ 5

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

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

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

Ответ 6

Примитивный:

String msg = "Please go to http://stackoverflow.com";
String withURL = msg.replaceAll("(?:https?|ftps?)://[\\w/%.-]+", "<a href='$0'>$0</a>");
System.out.println(withURL);

Это требует уточнения, соответствия правильных URL-адресов и, в частности, параметров GET (? foo = bar & x = 25)

Ответ 7

Вы задаете два отдельных вопроса.

  • Каков наилучший способ определения URL-адресов в строках? См. этот поток
  • Как закодировать вышеупомянутое решение на Java? другие ответы, иллюстрирующие использование String.replaceAll, рассмотрели это.

Ответ 8

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

Ответ 9

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

  • Его поток основан и может использоваться на больших документах
  • Его расширяемость для управления всеми видами "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);

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

Ответ 10

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

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

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

Ответ 11

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

Он поддерживает: html, email, (только мы) номер телефона, твиттер и хэштеги.

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

Ответ 13

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

if (yourtextview.getText().toString().contains("www") || yourtextview.getText().toString().contains("http://"){ your code here if contains URL;}