Created
April 28, 2016 23:09
-
-
Save attacco/0d09d4aa1d4b0e98a87f69a8a37dbf25 to your computer and use it in GitHub Desktop.
Method to wrap URL's in plain text to 'a href...' elements, like in html.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Map; | |
import java.util.NavigableMap; | |
import java.util.TreeMap; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
public class URLWrapUtil { | |
private final static Pattern A_HREF_PATTERN = Pattern.compile("(?i)<a\\s+href\\s*=\\s*\".+\"\\s*>.+<\\s*/\\s*a\\s*>"); | |
// Copied (and optimized) from android.util.Patterns#WEB_URL (SDK 23) | |
private final static Pattern URL_PATTERN = Pattern.compile("(?i)((?:(https?|rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?(?:(([a-zA-Z0-9 -\uD7FF豈-\uFDCFﷰ-\uFFEF]([a-zA-Z0-9 -\uD7FF豈-\uFDCFﷰ-\uFFEF\\-]{0,61}[a-zA-Z0-9 -\uD7FF豈-\uFDCFﷰ-\uFFEF]){0,1}\\.)+[a-zA-Z -\uD7FF豈-\uFDCFﷰ-\uFFEF]{2,63}|((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9]))))(?:\\:\\d{1,5})?)(\\/(?:(?:[a-zA-Z0-9 -\uD7FF豈-\uFDCFﷰ-\uFFEF\\;\\/\\?\\:\\@\\&\\=\\#\\~\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?(?:\\b|$)"); | |
public static String wrap(String source) { | |
if (source == null) { | |
return null; | |
} | |
// map of: start => end | |
final NavigableMap<Integer, Integer> entries = new TreeMap<>(); | |
Matcher m = A_HREF_PATTERN.matcher(source); | |
while (m.find()) { | |
entries.put(m.start(), m.end()); | |
} | |
m = URL_PATTERN.matcher(source); | |
final StringBuffer sb = new StringBuffer(); // appendReplacement method accepts only StringBuffer :( | |
while (m.find()) { | |
final int start = m.start(); | |
final Map.Entry<Integer, Integer> entry = entries.floorEntry(start); | |
/* | |
* Из серии "Предварительная оптимизация". | |
* Возможно, данный блок поможет ускорить работу в случае, если source довольно большой, причем, | |
* "<a href.../>" встречается только в начале, а дальше идут просто URL. | |
* С одной стороны, entries будет каждый раз отсекать уже пройденные вхождения, с другой, это приводит к | |
* созданию объекта, оборачивающего entries - map view, см. описание метода java.util.NavigableMap.tailMap(K, boolean)). | |
* | |
* По-умолчанию, предлагаю не использовать эту оптимизацию. | |
* */ | |
/*if (entry != null) { | |
entries = entries.tailMap(entry.getKey(), false); | |
}*/ | |
// we're should wrap if there is no entry, or our start position is greater than the end of 'danger' region. | |
final boolean shouldWrap = entry == null || start > entry.getValue(); | |
final String url = source.substring(start, m.end()); | |
final String replacement = shouldWrap ? String.format("<a href=\"%1$s\">%1$s</a>", url) : url; | |
m.appendReplacement(sb, replacement); | |
} | |
m.appendTail(sb); | |
return sb.toString(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment