webentwicklung-frage-antwort-db.com.de

So ermitteln Sie das Vorhandensein einer URL in einer Zeichenfolge

Ich habe eine Eingabe Zeichenkette sagen Please go to http://stackoverflow.com. Der URL-Teil des Strings wird erkannt und ein Anker <a href=""></a> wird automatisch von vielen Browser-/IDE/-Anwendungen hinzugefügt. So wird es Please go to <a href='http://stackoverflow.com'>http://stackoverflow.com</a>.

Ich muss das gleiche mit Java tun.

26
Rakesh N

Verwenden Sie dafür Java.net.URL !!

Warum verwenden Sie nicht die Kernklasse in Java für diese "Java.net.URL" und lassen Sie die URL überprüfen. 

Während der folgende Code gegen das Prinzip "Ausnahme nur für Ausnahmebedingungen verwenden" verstößt, ist es für mich nicht sinnvoll, das Rad für etwas neu zu erfinden, das auf der Java-Plattform völlig ausgereift ist.

Hier ist der Code:

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();
    }
}

Verwenden Sie die folgende Eingabe:

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

Erzeugt die folgende Ausgabe:

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>

Natürlich können verschiedene Protokolle auf unterschiedliche Weise gehandhabt werden. Sie können beispielsweise alle Informationen mit den Suchern der URL-Klasse abrufen 

 url.getProtocol();

Oder die restlichen Attribute: spec, port, file, query, ref usw. usw

http://Java.Sun.com/javase/6/docs/api/Java/net/URL.html

Behandelt alle Protokolle (zumindest alle, die der Java-Plattform bekannt sind) und als zusätzlichen Vorteil: Wenn eine URL vorhanden ist, die Java derzeit nicht erkennt und schließlich in die URL-Klasse (durch Aktualisieren der Bibliothek) aufgenommen wird, werden Sie erhalten es transparent!

56
OscarRyz

Obwohl es nicht Java-spezifisch ist, hat Jeff Atwood kürzlich einen Artikel über die Fallstricke veröffentlicht, auf die Sie stoßen könnten, wenn Sie versuchen, URLs in beliebigem Text zu finden und abzugleichen:

Das Problem mit URLs

Es gibt einen guten Regex, der zusammen mit dem Codeausschnitt verwendet werden kann, den Sie benötigen, um Parens richtig (mehr oder weniger) zu handhaben.

Der Regex:

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

Die Paren-Bereinigung:

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

Sie könnten so etwas tun (passen Sie den Regex an Ihre Bedürfnisse an):

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
Jason Coco

Der folgende Code nimmt diese Änderungen am "Atwood Approach" vor:

  1. Erkennt https zusätzlich zu http (das Hinzufügen anderer Schemas ist trivial)
  2. Das CASE_INSENSTIVE-Flag wird verwendet, da HtTpS: // gültig ist.
  3. Übereinstimmende Sätze von Klammern werden abgezogen (sie können auf Einer beliebigen Ebene verschachtelt werden). Darüber hinaus werden alle verbleibenden nicht übereinstimmenden linken Klammern Entfernt, aber nachfolgende rechte Klammern werden beibehalten (um URLs im Wikipedia-Stil zu respektieren). 
  4. Die URL ist im Linktext HTML-kodiert.
  5. Das Zielattribut wird über Methodenparameter übergeben. Andere Attribute können nach Wunsch hinzugefügt werden.
  6. Es verwendet\b nicht, um einen Word-Bruch zu identifizieren, bevor eine URL gefunden wird. URLs können mit einer linken Klammer oder mit http [s]: // beginnen, wobei keine anderen Anforderungen gestellt werden.

Anmerkungen:

  • Die StringUtils von Apache Commons Lang werden im folgenden Code verwendet
  • Der folgende Aufruf von HtmlUtil.encode () ist ein Util, das schließlich Einen Tomahawk-Code aufruft, um den Linktext mit HTML-Code zu kodieren, aber ein ähnliches Hilfsprogramm reicht aus.
  • Im Methodenkommentar finden Sie eine Verwendung in JSF oder anderen Umgebungen, in denen die Ausgabe standardmäßig HTML-codiert ist.

Dies wurde als Antwort auf die Anforderungen unseres Kunden geschrieben und ist unserer Meinung nach ein vernünftiger Kompromiss zwischen den zulässigen Zeichen des RFC und der allgemeinen Verwendung. Es wird hier in der Hoffnung angeboten, dass es für andere nützlich sein wird. 

Es könnte eine weitere Erweiterung vorgenommen werden, bei der beliebige Unicode-Zeichen eingegeben werden können (dh nicht mit% XX (zweistelliges Hex) gekennzeichnet und mit Hyperlinks versehen werden. Dies setzt jedoch die Annahme aller Unicode-Buchstaben sowie eine begrenzte Interpunktion und die Aufteilung auf die "akzeptablen" Trennzeichen voraus (zB.,%, |, # usw.), URL-Kodierung jedes Teils und anschließendes Zusammenkleben. Zum Beispiel http://en.wikipedia.org/wiki / Björn_Andrésen (das den Stack Überlaufgenerator erkennt nicht) wäre "http://en.wikipedia.org/wiki/Bj%C3%B6rn_Andr%C3%A9sen" in der href, würde jedoch Björn_Andrésen im verlinkten Text auf der Seite enthalten.

// 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 ()'s ... 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;

}
2
Jacob Zwiers

Ich habe eine kleine Bibliothek gemacht, die genau das macht:

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

Einige knifflige Beispiele und die gefundenen Links:

1
robinst

Für 2017 eine bequemere Vorgehensweise vorschlagen:

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

oder Android:autoLink="all" für alle Arten von Links.

0
Beeing Jk

Sie stellen zwei getrennte Fragen.

  1. Was ist der beste Weg, um URLs in Strings zu identifizieren? Siehe diesen Thread
  2. Wie codiere ich die obige Lösung in Java? Andere Antworten, die die Verwendung von String.replaceAll veranschaulichen, haben sich mit diesem Problem befasst
0
ykaganovich

Eine gute Verfeinerung der Antwort von PhiLho wäre: msg.replaceAll("(?:https?|ftps?)://[\w/%.-][/\??\w=?\w?/%.-]?[/\?&\w=?\w?/%.-]*", "$0");

0
Sérgio Nunes

Primitive:

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

Dies erfordert eine Verfeinerung, um richtige URLs und insbesondere GET-Parameter abzugleichen (? Foo = bar & x = 25).

0
PhiLho

Ich schrieb meinen eigenen URI/URL-Extraktor und stellte fest, dass es für jemanden nützlich sein könnte, wenn man bedenkt, dass es meiner Meinung nach besser ist als die anderen Antworten, weil:

  • Sein Stream basiert und kann für große Dokumente verwendet werden
  • Es ist erweiterbar, um alle Arten von "Atwood Paren" Problemen über eine Strategiekette abzuwickeln.

Da der Code für einen Beitrag etwas lang ist (wenn auch nur eine Java-Datei), habe ich ihn auf Gist github gestellt.

Hier ist eine Signatur einer der Hauptmethoden, um aufzurufen, wie die oben genannten Aufzählungspunkte gezeigt werden:

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

Es gibt eine Standardstrategiekette, die die meisten Atwood-Probleme behandelt.

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

Genießen!

0
Adam Gent