Skip to content

Instantly share code, notes, and snippets.

@anton-chernianu
Last active December 13, 2019 15:03
Show Gist options
  • Save anton-chernianu/757f7196a0f159288a2e64c1fb0ef23c to your computer and use it in GitHub Desktop.
Save anton-chernianu/757f7196a0f159288a2e64c1fb0ef23c to your computer and use it in GitHub Desktop.
JavaScript: Regex matching links without <a> and replace
function addTagToLinks(str) {
const httpRegex = "((?:(http|https|Http|Https|rtsp|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][a-zA-Z0-9\\-]{0,64}\\.)+" // named host
+ "(?:" // plus top level domain
+ "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ "|(?:biz|b[abdefghijmnorstvwyz])"
+ "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
+ "|d[ejkmoz]"
+ "|(?:edu|e[cegrstu])"
+ "|f[ijkmor]"
+ "|(?:gov|g[abdefghilmnpqrstuwy])"
+ "|h[kmnrtu]"
+ "|(?:info|int|i[delmnoqrst])"
+ "|(?:jobs|j[emop])"
+ "|k[eghimnrwyz]"
+ "|l[abcikrstuvy]"
+ "|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
+ "|(?:name|net|n[acefgilopruz])"
+ "|(?:org|om)"
+ "|(?:pro|p[aefghklmnrstwy])"
+ "|qa"
+ "|r[eouw]"
+ "|s[abcdeghijklmnortuvyz]"
+ "|(?:tel|travel|t[cdfghjklmnoprtvwz])"
+ "|u[agkmsyz]"
+ "|v[aceginu]"
+ "|w[fs]"
+ "|y[etu]"
+ "|z[amw]))"
+ "|(?:(?:25[0-5]|2[0-4]" // or ip address
+ "[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})?)" // plus option port number
+ "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
+ "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+ "(?:\\b|$)";
// выбираем ссылки, которые не следуют за аттрибутом href или которые не находятся перед закрывающим тегом </a>
const regex = "((?<href><a\\s+href=\")?" + httpRegex + ")(?<tag>(?!.*<\\/a>))";
let result = str.matchAll(new RegExp(regex, 'g'));
let strNew = str,
// каждая замена ссылки увеличивает длину оригинальной строки
// padding содержит кол-во символов, на которое увеличилась оригинальная строка после замены
padding = 0;
for (let item of result) {
// если ссылка находится после аттрибута href(группа href не undefined)
// или ссылка содержит закрывающий тег </a>
// то пропускаем эту ссылку
if (item.groups.href !== undefined || (item.groups.tag !== undefined && -1 !== item.groups.tag.indexOf('</a>'))) {
continue;
}
let insert = '<a href="' + item[0] + '">' + item[0] + "</a>",
startItemIndex = item.index + padding,
endItemIndex = startItemIndex + item[0].length;
strNew = strNew.slice(0, startItemIndex) + insert + strNew.slice(endItemIndex, strNew.length);
padding += (insert.length - item[0].length);
}
return strNew;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment