Lookbehind альтернатива с lookbehind и lookahead - PullRequest
3 голосов
/ 02 июня 2019

Я ищу регулярное выражение для разделения предоставленных пользователем строк на символ :, но не тогда, когда пользователь избежал двоеточия \: или его части, например, URL-адреса. https://stackoverflow... В javascript большинство браузеров пока не поддерживают вид сзади. Можно ли применить какой-то другой подход для части, которая находится позади?

В clojure / Clojurescript на Chrome (который поддерживает lookbehinds) это регулярное выражение делает свое дело:

#"(?<!\):(?!//)"

но не в Safari (например).

Ответы [ 3 ]

2 голосов
/ 02 июня 2019

Основная проблема заключается в том, что в настоящее время браузеры не поддерживают просмотр задним числом, который необходим для поиска и отмены префикса \, поэтому мы не включаем \:.

Один обходной путь (не оченьдовольно, но это работает) - сначала заменить \: на некоторый «символ», который, как вы знаете, не встречается в вашем тексте естественным образом, произведет разделение, а замена вернет любой \:.

Например, этот метод вернет пустой элемент "", если у вас есть "::" в вашей строке:

let regex = /:(?!\/\/)/

//original string literal \: has to be expressed as \\:
let str = "http://example.com::hello:dolly:12\\:00\\:PM";

//substitute out any \: 
str = str.replace(/\\:/g,"<colon>"); //http://example.com::hello:dolly:12<colon>00<colon>PM

//now we split 'normally' without lookbehind
let arr = str.split(regex); //[ 'http://example.com', '', 'hello', 'dolly', '12\\:00\\:PM' ]

//substitute back \:
arr = arr.map(element => element.replace(/<colon>/g, "\\:")); //[ 'http://example.com', '', 'hello', 'dolly', '12\\:00\\:PM' ]

console.log(arr);

Если вы просто посленепустые элементы, вы можете просто сделать на нем arr.filter(Boolean) или просто использовать соответствующее решение @ Skeeve, поскольку оно более элегантно для этой цели.

1 голос
/ 02 июня 2019

Вы также можете использовать заменить и передать функцию в качестве второго параметра.

Вы можете использовать шаблон для сопоставления с тем, что вам не нужно, и записать в группе то, чтоты хочешь сохранить.Затем вы можете заменить часть, которую вы хотите сохранить, маркером, как в подходе @chatnoir, а затем разбить на этот маркер.

:\/\/\S+|\\:|(:)

Пояснение

  • :\/\/\S+ Соответствие :// с последующим 1+ раз непробельным символом
  • | Или
  • \\: Соответствие \:
  • | или
  • (:) Захват : в группе 1

Regex demo

let pattern = /:\/\/\S+|\\:|(:)/g;
let str = "string\\: or https://www.example.com:8000 or split:me or te\\:st or \\:test or notsplit\\:me:splitted or \\: or ftp://example.com :";

str = str.replace(pattern, function(match, group1) {
  return group1 === undefined ? match : "<split>"
});

console.log(str.split("<split>").filter(Boolean));
1 голос
/ 02 июня 2019

Альтернативой может быть не поиск разделителя, а поиск элементов:

var str="this:is\\:a:test:https://stackoverflow:80:test::test";
var elements= str.match(/((?:[^\\:]|\\:|:\/\/)+)/g);
// elements= [ "this", "is\\:a", "test", "https://stackoverflow", "80", "test", "test" ]
  1. Элементы могут быть не пустыми (обратите внимание на «+» в регулярном выражении) и какотсутствует пустой элемент между последними 2 «тестами»
  2. Вы забыли, что URL может содержать несколько двоеточий.Как насчет `http://me:password@myhost.com:8080/path?value=d:f'

Кроме того, я думаю, что это должно работать для вас.

Я думаю, что вы можете преодолеть недостатки только с более или менее сложным циклом, используя regexp-exec.

PS Я знаю, что группировка здесь не требуется, но если вы хотите использовать ее в regexp-exec, она вам понадобится.Недостатки:

PPS Исправлена ​​опечатка @chatnoir найдена

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...