Ответ 1
Вы можете получить доступ к группам захвата следующим образом:
var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
var match = myRegexp.exec(myString);
console.log(match[1]); // abc
Я хочу сопоставить часть строки, используя регулярное выражение, а затем получить доступ к этой подстроке в скобках:
var myString = "something format_abc"; // I want "abc"
var arr = /(?:^|\s)format_(.*?)(?:\s|$)/.exec(myString);
console.log(arr); // Prints: [" format_abc", "abc"] .. so far so good.
console.log(arr[1]); // Prints: undefined (???)
console.log(arr[0]); // Prints: format_undefined (!!!)
Что я делаю неправильно?
Я обнаружил, что не было ничего плохого в коде регулярного выражения выше: фактическая строка, которую я тестировал, была следующей:
"date format_%A"
Сообщение о том, что "% A" undefined кажется очень странным поведением, но оно напрямую не связано с этим вопросом, поэтому я открыл новый, Почему совпадающая подстрока, возвращающая "undefined" в JavaScript?.
Проблема заключалась в том, что console.log
принимает свои параметры как оператор printf
, а поскольку строка, которую я записывал ("%A"
), имела специальное значение, она пыталась найти значение следующего параметра.
Вы можете получить доступ к группам захвата следующим образом:
var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
var match = myRegexp.exec(myString);
console.log(match[1]); // abc
Вот метод, который вы можете использовать для получения n-й группы захвата для каждого соответствия:
function getMatches(string, regex, index) {
index || (index = 1); // default to the first capturing group
var matches = [];
var match;
while (match = regex.exec(string)) {
matches.push(match[index]);
}
return matches;
}
// Example :
var myString = 'something format_abc something format_def something format_ghi';
var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;
// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);
// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);
var myString = "something format_abc";
var arr = myString.match(/\bformat_(.*?)\b/);
console.log(arr[0] + " " + arr[1]);
Что касается приведенных выше примеров круглых скобок с несколькими совпадениями, я искал ответ здесь, не получив от него:
var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm);
Посмотрев на несколько запутанные вызовы функций с while и .push() выше, мне стало ясно, что проблема может быть решена очень элегантно с помощью mystring.replace() вместо этого (замена не является точкой, а isn ' t даже сделано, функция CLEAN, встроенная функция рекурсивного вызова функции для второго параметра:!):
var yourstring = 'something format_abc something format_def something format_ghi';
var matches = [];
yourstring.replace(/format_([^\s]+)/igm, function(m, p1){ matches.push(p1); } );
После этого я не думаю, что когда-нибудь снова буду использовать .match(), чтобы больше ничего не сделать.
И последнее, но не менее важное: я нашел одну строку кода, которая отлично сработала для меня (JS ES6):
let reg = /#([\S]+)/igm; // Get hashtags.
let string = 'mi alegría es total! ✌🙌\n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris';
let matches = (string.match(reg) || []).map(e => e.replace(reg, '$1'));
console.log(matches);
someString.match(regexPattern)
./format_(.*?)/g
, где (.*?)
будет подобранной группой.) Они находятся внутри сопоставленных шаблонов.Чтобы получить доступ к сопоставленным группам, в каждом из совпадающих шаблонов вам нужна функция или что-то похожее на итерацию по сравнению. Есть несколько способов сделать это, как показывают многие другие ответы. Большинство других ответов используют цикл while для итерации по всем сопоставленным шаблонам, но я думаю, что мы все знаем потенциальные опасности с этим подходом. Нужно сопоставлять с new RegExp()
вместо самого шаблона, который упоминается только в комментарии. Это связано с тем, что метод .exec()
ведет себя аналогично функции генератора - он останавливается каждый раз, когда есть соответствие, но сохраняет свой .lastIndex
в продолжите оттуда при следующем вызове .exec()
.
Ниже приведен пример функции searchString
, которая возвращает Array
всех совпадающих шаблонов, где каждый match
является Array
со всеми содержащимися согласованными группами. Вместо использования цикла while я представил примеры, используя как функцию Array.prototype.map()
, так и более эффективный способ - используя простой for
-loop.
Они менее эффективны, поскольку они в основном реализуют forEach
-loop вместо более быстрого for
-loop.
// Concise ES6/ES2015 syntax
const searchString =
(string, pattern) =>
string
.match(new RegExp(pattern.source, pattern.flags))
.map(match =>
new RegExp(pattern.source, pattern.flags)
.exec(match));
// Or if you will, with ES5 syntax
function searchString(string, pattern) {
return string
.match(new RegExp(pattern.source, pattern.flags))
.map(match =>
new RegExp(pattern.source, pattern.flags)
.exec(match));
}
let string = "something format_abc",
pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;
let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag
// Performant ES6/ES2015 syntax
const searchString = (string, pattern) => {
let result = [];
const matches = string.match(new RegExp(pattern.source, pattern.flags));
for (let i = 0; i < matches.length; i++) {
result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
}
return result;
};
// Same thing, but with ES5 syntax
function searchString(string, pattern) {
var result = [];
var matches = string.match(new RegExp(pattern.source, pattern.flags));
for (var i = 0; i < matches.length; i++) {
result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
}
return result;
}
let string = "something format_abc",
pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;
let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag
Мне еще предстоит сравнить эти альтернативы с теми, которые были упомянуты ранее в других ответах, но я сомневаюсь, что этот подход менее эффективен и менее безопасен, чем другие.
Ваш синтаксис, вероятно, не лучший. FF/Gecko определяет RegExp как расширение функции.
(FF2 дошел до typeof(/pattern/) == 'function'
)
Кажется, это специфично для FF - IE, Opera и Chrome - все исключения для него исключают.
Вместо этого используйте метод, ранее упомянутый другими: RegExp#exec
или String#match
.
Они дают одинаковые результаты:
var regex = /(?:^|\s)format_(.*?)(?:\s|$)/;
var input = "something format_abc";
regex(input); //=> [" format_abc", "abc"]
regex.exec(input); //=> [" format_abc", "abc"]
input.match(regex); //=> [" format_abc", "abc"]
Нет необходимости вызывать метод exec
! Вы можете использовать метод "match" непосредственно в строке. Просто не забудьте скобки.
var str = "This is cool";
var matches = str.match(/(This is)( cool)$/);
console.log( JSON.stringify(matches) ); // will print ["This is cool","This is"," cool"] or something like that...
Позиция 0 имеет строку со всеми результатами. Позиция 1 имеет первое совпадение, представленное круглыми скобками, а позиция 2 имеет второе совпадение, выделенное в ваших круглых скобках. Вложенные круглые скобки сложны, поэтому будьте осторожны!
String#matchAll
(см. Черновик этапа 3/предложение от 7 декабря 2018 года) упрощает доступ ко всем группам в объекте сопоставления (имейте в виду, что группа 0 - это полное совпадение, в то время как остальные группы соответствуют группам захвата в шаблоне):
С
matchAll
доступен, вы можете избежатьwhile
цикл иexec
с/g
... Вместо этого, с помощьюmatchAll
, вы получите обратно итератор, который вы можете использовать с более удобнымfor...of
, распространения массива, илиArray.from()
конструкции
Этот метод выдает результаты, аналогичные Regex.Matches
в С#, re.finditer
в Python, preg_match_all
в PHP.
См. Демонстрацию JS (протестировано в Google Chrome 73.0.3683.67 (официальная сборка), бета-версия (64-разрядная версия)):
var myString = "key1:value1, [email protected]=value3";
var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
console.log([...matches]); // All match with capturing group values
Один вкладыш, который практичен, только если у вас есть одна пара скобок:
while ( ( match = myRegex.exec( myStr ) ) && matches.push( match[1] ) ) {};
Использование вашего кода:
console.log(arr[1]); // prints: abc
console.log(arr[0]); // prints: format_abc
Изменить: Safari 3, если это имеет значение.
function getMatches(string, regex, index) {
index || (index = 1); // default to the first capturing group
var matches = [];
var match;
while (match = regex.exec(string)) {
matches.push(match[index]);
}
return matches;
}
// Example :
var myString = 'Rs.200 is Debited to A/c ...2031 on 02-12-14 20:05:49 (Clear Bal Rs.66248.77) AT ATM. TollFree 1800223344 18001024455 (6am-10pm)';
var myRegEx = /clear bal.+?(\d+\.?\d{2})/gi;
// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);
// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);
С es2018 вы можете теперь String.match()
с именованными группами, делает ваше регулярное выражение более явным из того, что он пытался сделать.
const url =
'https://stackoverflow.com/questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regular-expression?some=parameter';
const regex = /(?<protocol>https?):\/\/(?<hostname>[\w-\.]*)\/(?<pathname>[\w-\./]+)\??(?<querystring>.*?)?$/;
const { groups: segments } = url.match(regex);
console.log(segments);
и вы получите что-то вроде
{protocol: "https", имя хоста: "stackoverflow.com", имя пути: "questions/432493/how-do-you-you-access-the-matched-groups-in-a-javascript-регулярное выражение", строка запроса: " некоторые = параметр "}
Ваш код работает для меня (FF3 на Mac), даже если я согласен с PhiLo, что регулярное выражение должно быть:
/\bformat_(.*?)\b/
(Но, конечно, я не уверен, потому что не знаю контекста регулярного выражения.)
/*Regex function for extracting object from "window.location.search" string.
*/
var search = "?a=3&b=4&c=7"; // Example search string
var getSearchObj = function (searchString) {
var match, key, value, obj = {};
var pattern = /(\w+)=(\w+)/g;
var search = searchString.substr(1); // Remove '?'
while (match = pattern.exec(search)) {
obj[match[0].split('=')[0]] = match[0].split('=')[1];
}
return obj;
};
console.log(getSearchObj(search));
Вам на самом деле не нужен явный цикл для анализа нескольких совпадений - передайте функцию замены в качестве второго аргумента, как описано в: String.prototype.replace(regex, func)
:
var str = "Our chief weapon is {1}, {0} and {2}!";
var params= ['surprise', 'fear', 'ruthless efficiency'];
var patt = /{([^}]+)}/g;
str=str.replace(patt, function(m0, m1, position){return params[parseInt(m1)];});
document.write(str);
Мы можем получить доступ к сопоставленной группе в регулярных выражениях, используя обратную косую черту, за которой следует номер соответствующей группы:
/([a-z])\1/
В коде \1 представлено соответствие первой группе ([az])
Посмотрите эту ссылку на уроке 12:
Вы можете группировать символы, используя специальные
(
и)
(круглые скобки). Чтобы записать файл изображения, напишите выражение^(IMG(\d+))\.png$
.
function get_transaction_type_medium(sms_body) {
if (sms_body.toLowerCase().includes("is debited to a/c") && sms_body.toLowerCase().includes("at atm")) {
return ["ATM", "M"];
}
else {
return [null, null];
}
}
Получить все вхождения группы
let m=[], s = "something format_abc format_def format_ghi";
s.replace(/(?:^|\s)format_(.*?)(?:\s|$)/g, (x,y)=> m.push(y));
console.log(m);