Группа регулярных выражений, не исключая точек - PullRequest
3 голосов
/ 13 марта 2019

Допустим, у меня есть следующая строка: div.classOneA.classOneB#idOne

Попытка написать регулярное выражение, которое извлекает из него классы (classOneA, classOneB). Я смог сделать это, но только с Lookbehind утверждением .

Это выглядит так:

'div.classOneA.classOneB#idOne'.match(/(?<=\.)([^.#]+)/g)
> (2) ["classOneA", "classOneB"]

Теперь я хотел бы заархивировать это без подхода «назад» и не понимаю, почему мое решение не работает.

'div.classOneA.classOneB#idOne'.match(/\.([^.#]+)/g)
> (2) [".classOneA", ".classOneB"]

Думал, что группировка решит мою проблему, но все соответствующие элементы также содержат точку.

Ответы [ 6 ]

1 голос
/ 13 марта 2019

Это потому, что с модификатором g вы получаете все подходящие подстроки, но не соответствующие им группы (то есть, как если бы (...) пары работали так же, как (?:...) единицы.

Вы видите. Без модификатора g:

> 'div.classOneA.classOneB#idOne'.match(/\.([^.#]+)/)
[ '.classOneA',
  'classOneA',
  index: 3,
  input: 'div.classOneA.classOneB#idOne',
  groups: undefined ]

С g модификатором:

> 'div.classOneA.classOneB#idOne'.match(/\.([^.#]+)/g)
[ '.classOneA', '.classOneB' ]

Другими словами: вы получаете все совпадения, но только одно совпадение (0 предметов) для каждого.

Есть много решений:

  1. Используйте LookBehind утверждений, как вы указали сами.

  2. Исправьте каждый результат позже, добавив .map(x=>x.replace(/^\./, ""))

  3. Или, если ваша структура ввода не будет намного более сложной, чем приведенный вами пример, просто используйте более дешевый подход:

    > 'div.classOneA.classOneB#idOne'.replace(/#.*/, "").split(".").slice(1)
    [ 'classOneA', 'classOneB' ]
    
  4. Используйте .replace() + обратный вызов вместо .match(), чтобы иметь возможность получить доступ к группам захвата каждого матча:

    const str = 'div.classOneA.classOneB#idOne';
    const matches = [];
    str.replace(/\.([^.#]+)/g, (...args)=>matches.push(args[1]))
    console.log(matches); // [ 'classOneA', 'classOneB' ]
    

Я бы порекомендовал третий (если нет других возможных входов, которые могли бы в итоге его сломать), потому что он гораздо более эффективен (фактические регулярные выражения используются только один раз для обрезки части '#idOne').

1 голос
/ 13 марта 2019

В Javascript нет хорошего способа как сопоставлять несколько раз (опция / g), так и подбирать группы захвата (в скобках).Попробуйте это:

var input = "div.classOneA.classOneB#idOne";
var regex = /\.([^.#]+)/g;

var matches, output = [];
while (matches = regex.exec(input)) {
    output.push(matches[1]);
}
0 голосов
/ 13 марта 2019

Я не эксперт по использованию регулярных выражений - особенно в Javascript - но после некоторого исследования MDN я выяснил, почему ваша попытка не сработала, и как исправить.

Проблема в том, что при использовании .match с регулярным выражением с флагом /g игнорируются группы захвата . Таким образом, вместо этого вы должны использовать метод .exec для объекта regexp, используя цикл для его многократного выполнения для получения всех результатов.

Таким образом, следующий код работает и может быть адаптирован для подобных случаев. (Обратите внимание, что grp[1] - это потому, что первый элемент массива, возвращаемый .exec, является полным совпадением, группы - последующими элементами.)

var regExp = /\.([^.#]+)/g
var result = [];
var grp;
while ((grp = regExp.exec('div.classOneA.classOneB#idOne')) !== null) {
  result.push(grp[1]);
}
console.log(result)
0 голосов
/ 13 марта 2019

Если вы хотите расширить, вы regex.Вы можете просто map на результаты и заменить . на пустую строку

let op = 'div.classOneA.classOneB#idOne'.match(/\.([^.#]+)/g)
         .map(e=> e.replace(/\./g,''))

console.log(op)
0 голосов
/ 13 марта 2019

Это регулярное выражение будет работать без утверждения с задним числом:

'div.classOneA.classOneB#idOne'.match(/\.[^\.#]+/g).map(item => item.substring(1));

Утверждение с задним видом не доступно в JavaScript в последнее время.

0 голосов
/ 13 марта 2019

Если вы знаете, что ищете текст, содержащий class, тогда вы можете использовать что-то вроде

'div.classOneA.classOneB#idOne'.match(/class[^.#]+/g)

Если вам известно только то, что тексту предшествует точка, то выдолжен использовать lookbehind.

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