Regex для сопоставления буквенно-цифровых символов в строке, содержащей URL

1

Учитывая несколько сценариев, как я могу сопоставить и извлечь буквенно-цифровые символы (и символы) в строке, содержащей 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, если это возможно.

  • 0
    Может быть несколько подстрок не-URL? (в каком случае вы хотите массив этих подстрок?)
  • 0
    Все ли URL начинаются с протокола?
Теги:
google-apps-script

3 ответа

2
Лучший ответ

Мы можем захватить любой последовательный текст, за исключением того, что выглядит как 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|$)

Демо с вашим набором символов заголовка

  • 0
    Это также соответствует лидирующим пробелам, что, вероятно, нежелательно.
  • 0
    Group1 захватывает текст, который не содержит пробелов.
Показать ещё 2 комментария
1

Одной из возможностей может быть совпадение, пока вы не встретите первый 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()));
  • 0
    Это зависит от подстрок, не относящихся к URL, начиная с границы слова, и, к сожалению, внешний вид (для пробела или для ^ ) недостаточно широко поддерживается, как вы, наверное, знаете, не знаете, как бы я это исправил
  • 0
    @CertainPerformance Я вижу, что вы имеете в виду, я также добавил заменяющий вариант.
0

Вы можете использовать .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));
  • 0
    Другой вариант - это .replace() URL с пустой строкой, используя urlRegexp s.replace(/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/g, '')

Ещё вопросы

Сообщество Overcoder
Наверх
Меню