Учитывая несколько сценариев, как я могу сопоставить и извлечь буквенно-цифровые символы (и символы) в строке, содержащей URL-адреса? В настоящее время я использую Google Apps Script для извлечения простого основного текста текста с гиперссылкой из сообщения потока Gmail, и в основном я хотел бы сопоставить и извлечь заголовок из некоторых строк следующим образом:
var scenario1 = "Testing: Stack Overflow Title 123? https://www.stackoverflow.com";
... в котором я хотел бы выводить только: "Testing: Stack Overflow Title 123?"
Вот еще один сценарий:
var scenario2 = "https://www.stackoverflow.com Testing: Stack Overflow Title 123? https://www.stackoverflow.com";
... снова, в котором я хотел бы выводить только: "Testing: Stack Overflow Title 123?"
Я попробовал следующее для первоначального тестирования, чтобы увидеть, содержит ли String сначала URL-адрес (в котором я подтвердил, что регулярное выражение для сопоставления URL-адресов работает и выводит: https://www.stackoverflow.com), а затем проверяет, существует ли заголовок, чтобы в конечном итоге извлечь его, но безрезультатно:
var scenario1 = "Testing: Stack Overflow Title 123? https://www.stackoverflow.com";
var scenario2 = "https://www.stackoverflow.com Testing: Stack Overflow Title 123? https://www.stackoverflow.com";
var urlRegex = /(http|https|ftp|ftps)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?/;
var titleRegex = /^[a-zA-Z0-9_:?']*$/;
var containsUrl = urlRegex.test(element);
if (containsUrl) {
var containsTitle = titleRegex.test(scenario1);
if (containsTitle) { // No match, and doesn't run
var title = titleRegex.exec(element)[0];
Logger.log("title: " + title);
}
}
По сути, мне нужен шаблон Regex, который соответствует ВСЕМ, кроме URL-адресов, если это возможно.
Будут ли все URL-адреса начинаться с протокола?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Одной из возможностей может быть сопоставление до тех пор, пока вы не встретите первый URL-адрес, используя либо группу, либо положительный просмотр вперед.
Использование положительного прогноза, который может выглядеть так:
\bTesting: .*?(?=\s*(?:https?|ftps?)://)
const regexLookahead = /\bTesting: .*?(?=\s*(?:https?|ftps?)://)/;
[
"Testing: Stack Overflow Title 123? https://www.stackoverflow.com",
"https://www.stackoverflow.com Testing: Stack Overflow Title 123? https://www.stackoverflow.com"
].forEach(s => console.info(s.match(regexLookahead)[0]));Используя группу захвата, где ваше значение будет в первой группе захвата:
(\bTesting: .*?)\s*(?:https?|ftps?)://
const regexGroup = /(\bTesting: .*?)\s*(?:https?|ftps?):///;
[
"Testing: Stack Overflow Title 123? https://www.stackoverflow.com",
"https://www.stackoverflow.com Testing: Stack Overflow Title 123? https://www.stackoverflow.com"
].forEach(s => console.info(s.match(regexGroup)[1]));Если вы хотите сохранить все, кроме URL-адресов, вы можете сопоставить их и заменить пустой строкой:
\s*(?:https?|ftps?)://\S+
[
"Testing: Stack Overflow Title 123? https://www.stackoverflow.com",
"https://www.stackoverflow.com Testing: Stack Overflow Title 123? https://www.stackoverflow.com",
"https://www.stackoverflow.com test https://www.stackoverflow.com test https://www.stackoverflow.com test",
"https://www.stackoverflow.com test",
"test https://www.stackoverflow.com"
].forEach(s => console.info(s.replace(/\s*(?:https?|ftps?)://\S+/g, '').trim()));Однако это зависит от подстрок, отличных от URL, начинающихся с границы слова, и, к сожалению, просмотр назад (для пробела или для ^) пока недостаточно широко поддерживается, как вы, вероятно, знаете, не уверен, как я это исправлю
@CertainPerformance Я вижу, вы имеете в виду, что я также добавил заменяющий вариант.
Вы можете использовать символы пробела .split() и результирующий массив .filter(), чтобы исключить элементы, которые начинаются с указанных протоколов или заканчиваются словом, затем символом точки, затем словом и концом строки.
const splitURL = s => s.split` `.filter(w => !/^\w+(?=://)|\w+\.\w+$/.test(w)).join` `;
var scenario1 = "Testing: Stack Overflow Title 123? https://www.stackoverflow.com";
var scenario2 = "https://www.stackoverflow.com Testing: Stack Overflow Title 123? https://www.stackoverflow.com";
console.info(splitURL(scenario1), splitURL(scenario2));Другой вариант - .replace() URL с пустой строкой, используя urlRegexps.replace(/(http|https|ftp|ftps)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?/g, '')
Мы можем захватить любой последовательный текст, за исключением того, что выглядит как URL-адрес, используя это регулярное выражение,
(?:^|\s+)((?:(?!://).)*)(?=\s|$)
Объяснение:
(?:^|\s) — соответствует либо началу строки, либо одному или нескольким пробелам.((?:(?!://).)*) — Соответствует любому тексту, кроме того, который содержит ://, буквально идентифицируя его как URL-адрес.(?=\s|$) - Положительный просмотр вперед, чтобы убедиться, что за ним следует пробел или конец строкиЭто соответствует и фиксирует любой последовательный текст, кроме URL-адресов. Надеюсь, что это работает для вас.
Вот демонстрация Javascript.
var arr = ['Testing1: Stack Overflow Title 123? https://www.stackoverflow.com','https://www.stackoverflow.com Testing2: Stack Overflow Title xyz? https://www.stackoverflow.com Hello this is simple text ftp://www.downloads.com/']
for (s of arr) {
var reg = /(?:^|\s+)((?:(?!://).)*)(?=\s|$)/g;
match = reg.exec(s);
while (match != null) {
console.info(match[1])
match = reg.exec(s);
}
}Кроме того, как я вижу, вы хотите ограничить количество символов в соответствующем заголовке, вы можете использовать свой набор символов [a-zA-Z0-9_:?' ] (добавлен пробел в вашем наборе символов, чтобы также можно было записывать пробелы) вместо . в моем регулярном выражении и использовать следующее регулярное выражение, чтобы быть более точным, чтобы избежать захвата заголовка с непредусмотренными символами,
(?:^|\s+)((?:(?!://)[a-zA-Z0-9_:?' ])*)(?=\s|$)
Демонстрация с вашим набором символов заголовка
Это также соответствует ведущим пробелам, что, вероятно, нежелательно.
Group1 захватывает текст, который не содержит пробелов.
Я мог бы использовать положительный просмотр для целых совпадений, чтобы не содержать лишних пробелов, но многие старые инструменты/браузеры не поддерживают EcmaScript2018, и, следовательно, все они не будут работать, поэтому пришлось использовать групповой захват. И группа не содержит дополнительных начальных/конечных пробелов, как видно из моей демонстрации, которая должна работать для OP.
@PushpeshKumarRajwanshi +1 отлично
Может ли быть несколько подстрок, отличных от URL? (в каком случае вам нужен массив этих подстрок?)