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.
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!
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:
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);
}
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>");
Der folgende Code nimmt diese Änderungen am "Atwood Approach" vor:
Anmerkungen:
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><a href="..."></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;
}
Ich habe eine kleine Bibliothek gemacht, die genau das macht:
https://github.com/robinst/autolink-Java
Einige knifflige Beispiele und die gefundenen Links:
http://example.com.
→ http://example.com .http://example.com,
→ http://example.com ,(http://example.com)
→ ( http://example.com )(... (see http://example.com))
→ (... (siehe http://example.com ))https://en.wikipedia.org/wiki/Link_(The_Legend_of_Zelda)
→ https://en.wikipedia.org/wiki/Link_(The_Legend_of_Zelda)http://üñîçøðé.com/
→ http: //üñîçøðé.com/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.
Sie stellen zwei getrennte Fragen.
String.replaceAll
veranschaulichen, haben sich mit diesem Problem befasstEine gute Verfeinerung der Antwort von PhiLho wäre: msg.replaceAll("(?:https?|ftps?)://[\w/%.-][/\??\w=?\w?/%.-]?[/\?&\w=?\w?/%.-]*", "$0");
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).
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:
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!