Учитывая несколько сценариев, как я могу сопоставить и извлечь буквенно-цифровые символы (и символы) в строке, содержащей URL-адреса? В настоящее время я использую Google Apps Script для извлечения обычного основного текста гиперссылки из сообщения цепочки Gmail, и я бы хотел сопоставить и извлечь заголовок из некоторых строк следующим образом:
var scenario1 = "Testing: Stack Overflow Title 123? https://www.stackoverflow.com";
... в котором я хотел бы только вывести: "Testing: Qaru Title 123?"
Здесь другой сценарий:
var scenario2 = "https://www.stackoverflow.com Testing: Stack Overflow Title 123? https://www.stackoverflow.com";
... опять же, в котором я хотел бы только вывести: "Testing: Qaru Title 123?"
Я попробовал следующее для первоначального тестирования, чтобы увидеть, содержит ли строка сначала 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, используя это регулярное выражение,
(?:^|\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.log(match[1])
match = reg.exec(s);
}
}
Кроме того, как я вижу, вы хотите ограничить количество символов в соответствующем заголовке, вы можете использовать свой набор символов [a-zA-Z0-9_:?' ]
[a-zA-Z0-9_:?' ]
(добавлен пробел в вашем наборе символов, чтобы также разрешать захват пробелов) вместо .
в моем регулярном выражении и используйте следующее регулярное выражение, чтобы быть более точным, чтобы избежать захвата названия, имеющего непреднамеренные символы,
(?:^|\s+)((?:(?!:\/\/)[a-zA-Z0-9_:?' ])*)(?=\s|$)
Одной из возможностей может быть совпадение, пока вы не встретите первый 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.log(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.log(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.log(s.replace(/\s*(?:https?|ftps?):\/\/\S+/g, '').trim()));
^
) недостаточно широко поддерживается, как вы, наверное, знаете, не знаете, как бы я это исправил
Вы можете использовать .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.log(splitURL(scenario1), splitURL(scenario2));
.replace()
URL с пустой строкой, используя urlRegexp
s.replace(/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/g, '')