내가 아는 한 JavaScript에는 캡쳐 그룹이라는 것과 같은 것이 없습니다. 유사한 기능을 얻는 다른 방법은 무엇입니까?
내가 아는 한 JavaScript에는 캡쳐 그룹이라는 것과 같은 것이 없습니다. 유사한 기능을 얻는 다른 방법은 무엇입니까?
답변:
ECMAScript 2018에서는 명명 된 캡처 그룹 을 JavaScript 정규식에 도입했습니다 .
예:
const auth = 'Bearer AUTHORIZATION_TOKEN'
const { groups: { token } } = /Bearer (?<token>[^ $]*)/.exec(auth)
console.log(token) // "Prints AUTHORIZATION_TOKEN"
구형 브라우저를 지원 해야하는 경우 명명 된 캡처 그룹으로 할 수있는 일반 (번호 매기기) 캡처 그룹으로 모든 작업을 수행 할 수 있습니다. 번호를 추적하면됩니다-그룹에서 그룹을 캡처하는 순서가 번거 롭다면 번거로울 수 있습니다 정규식 변경.
내가 생각할 수있는 명명 된 캡처 그룹의 두 가지 "구조적"장점은 다음과 같습니다.
일부 정규 표현식 맛 (내가 아는 한 .NET 및 JGSoft)에서는 정규 표현식의 다른 그룹에 동일한 이름을 사용할 수 있습니다 ( 여기에서 중요한 예는 여기 참조 ). 그러나 대부분의 정규 표현식은이 기능을 지원하지 않습니다.
숫자로 둘러싸인 상황에서 번호가 매겨진 캡처 그룹을 참조해야하는 경우 문제가 발생할 수 있습니다. 하자 당신이 자리에 0을 추가 할 따라서 교체 할 말 (\d)
과 함께 $10
. 자바 스크립트,이 의지 (당신이 당신의 정규식에서 10 개 미만의 캡처 그룹을 가지고 같은) 작동하지만 펄은 역 참조 번호를 찾고 있다고 생각합니다 10
대신 숫자의 1
다음에 0
. Perl에서는 ${1}0
이 경우에 사용할 수 있습니다 .
그 외에, 명명 된 포획 그룹은 단지 "구문 설탕"이다. 캡처 그룹은 실제로 필요할 때만 사용 (?:...)
하고 다른 모든 상황에서는 캡처되지 않은 그룹을 사용하는 데 도움이됩니다 .
JavaScript의 더 큰 문제는 (제 생각에) 읽기 쉬운 복잡한 정규 표현식을 훨씬 쉽게 만들 수있는 자세한 정규 표현식을 지원하지 않는다는 것입니다.
Steve Levithan의 XRegExp 라이브러리 는 이러한 문제를 해결합니다.
추가 구문, 플래그 및 메소드에 대한 지원을 포함하여 정규 표현식의 확장되고 확장 가능한 크로스 브라우저 구현 인 XRegExp 를 사용할 수 있습니다 .
s
도트하는 모든 문자와 일치하기를 (일명 DOTALL 또는 만일 Singleline 모드) 및 x
자유 공간과 의견 (일명 확장 모드)에 대한.또 다른 가능한 해결책 : 그룹 이름과 색인을 포함하는 객체를 만듭니다.
var regex = new RegExp("(.*) (.*)");
var regexGroups = { FirstName: 1, LastName: 2 };
그런 다음 객체 키를 사용하여 그룹을 참조하십시오.
var m = regex.exec("John Smith");
var f = m[regexGroups.FirstName];
이것은 정규 표현식의 결과를 사용하여 코드의 가독성 / 품질을 향상 시키지만 정규 표현식 자체의 가독성은 향상시키지 않습니다.
ES6에서는 배열 파괴를 사용하여 그룹을 잡을 수 있습니다.
let text = '27 months';
let regex = /(\d+)\s*(days?|months?|years?)/;
let [, count, unit] = regex.exec(text) || [];
// count === '27'
// unit === 'months'
주의:
let
는 결과 배열의 첫 번째 값을 건너 뜁니다. 이는 전체 일치 문자열입니다.|| []
후에는 .exec()
더 일치 (때문에이없는 경우 destructuring 오류를 방지 할 수 .exec()
반환됩니다 null
)String.prototype.match
위치 0에있는 일치하는 전체 문자열과 그 이후의 그룹이 포함 된 배열을 반환합니다. 첫 번째 쉼표는 "0 위치에서 요소 건너 뛰기"라고 말합니다
RegExp.prototype.exec
이상 String.prototype.match
문자열 수있는 곳에 null
나 undefined
.
업데이트 : 마침내 JavaScript로 만들었습니다 (ECMAScript 2018)!
명명 된 캡처 그룹은 곧 JavaScript로 만들 수 있습니다.
이에 대한 제안은 이미 3 단계에 있습니다.
캡처 그룹에는 (?<name>...)
식별자 이름에 대한 구문을 사용하여 각괄호 안에 이름을 지정할 수 있습니다 . 날짜의 정규 표현식은로 쓸 수 있습니다 /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u
. 각 이름은 고유해야하며 ECMAScript IdentifierName 의 문법을 따라야합니다 .
명명 된 그룹은 정규식 결과의 그룹 속성의 속성에서 액세스 할 수 있습니다. 명명되지 않은 그룹과 마찬가지로 그룹에 대한 번호가 지정된 참조도 작성됩니다. 예를 들면 다음과 같습니다.
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = re.exec('2015-01-02');
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';
// result[0] === '2015-01-02';
// result[1] === '2015';
// result[2] === '01';
// result[3] === '02';
let {year, month, day} = ((result) => ((result) ? result.groups : {}))(re.exec('2015-01-02'));
node.js 프로젝트에서 사용할 수있는 named-regexp라는 node.js 라이브러리가 있습니다 (브라우저에서 browserify 또는 기타 패키징 스크립트로 라이브러리를 패키징하여 브라우저에서). 그러나 명명되지 않은 캡처 그룹이 포함 된 정규식에는 라이브러리를 사용할 수 없습니다.
정규식에서 오프닝 캡처 중괄호를 세면 정규 표현식에서 명명 된 캡처 그룹과 번호가 매겨진 캡처 그룹 사이에 매핑을 만들고 자유롭게 혼합하고 일치시킬 수 있습니다. 정규식을 사용하기 전에 그룹 이름을 제거하면됩니다. 나는 그것을 보여주는 세 가지 기능을 작성했습니다. 이 요지를 참조하십시오 : https://gist.github.com/gbirke/2cc2370135b665eee3ef
으로 팀 Pietzcker는 ECMAScript를 2018 소개합니다 자바 스크립트 정규 표현식에로 그룹을 캡처 명명했다. 그러나 위의 답변에서 찾지 못한 것은 정규 표현식 자체에서 명명 된 캡처 된 그룹 을 사용하는 방법이었습니다 .
이 구문으로 명명 된 캡처 그룹을 사용할 수 있습니다 \k<name>
. 예를 들어
var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/
Forivin 은 다음 과 같이 객체 결과에 캡처 된 그룹을 사용할 수 있다고 말했습니다.
let result = regexObj.exec('2019-28-06 year is 2019');
// result.groups.year === '2019';
// result.groups.month === '06';
// result.groups.day === '28';
var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/mgi;
function check(){
var inp = document.getElementById("tinput").value;
let result = regexObj.exec(inp);
document.getElementById("year").innerHTML = result.groups.year;
document.getElementById("month").innerHTML = result.groups.month;
document.getElementById("day").innerHTML = result.groups.day;
}
td, th{
border: solid 2px #ccc;
}
<input id="tinput" type="text" value="2019-28-06 year is 2019"/>
<br/>
<br/>
<span>Pattern: "(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>";
<br/>
<br/>
<button onclick="check()">Check!</button>
<br/>
<br/>
<table>
<thead>
<tr>
<th>
<span>Year</span>
</th>
<th>
<span>Month</span>
</th>
<th>
<span>Day</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span id="year"></span>
</td>
<td>
<span id="month"></span>
</td>
<td>
<span id="day"></span>
</td>
</tr>
</tbody>
</table>
당신은 바닐라 자바 스크립트를 사용하여이 작업을 수행 할 수는 없지만, 아마도 당신은 몇 가지 사용할 수있는 Array.prototype
같은 기능을 Array.prototype.reduce
일부 사용하여 명명 사람에 인덱스 일치를 설정하는 마법 .
분명히 다음 해결책은 일치하는 순서대로 발생해야합니다.
// @text Contains the text to match
// @regex A regular expression object (f.e. /.+/)
// @matchNames An array of literal strings where each item
// is the name of each group
function namedRegexMatch(text, regex, matchNames) {
var matches = regex.exec(text);
return matches.reduce(function(result, match, index) {
if (index > 0)
// This substraction is required because we count
// match indexes from 1, because 0 is the entire matched string
result[matchNames[index - 1]] = match;
return result;
}, {});
}
var myString = "Hello Alex, I am John";
var namedMatches = namedRegexMatch(
myString,
/Hello ([a-z]+), I am ([a-z]+)/i,
["firstPersonName", "secondPersonName"]
);
alert(JSON.stringify(namedMatches));
var assocArray = Regex("hello alex, I am dennis", "hello ({hisName}.+), I am ({yourName}.+)");
RegExp
프로토 타입에 함수를 추가 하여 오브젝트를 확장 할 수 있습니다 .
ECMAScript 2018이 없습니까?
저의 목표는 이름이 지정된 그룹에 익숙한 것과 최대한 비슷하게 작동하는 것이 었습니다. ECMAScript 2018 ?<groupname>
에서는 그룹 내에 배치 하여 명명 된 그룹을 표시 할 수 있지만, 이전 자바 스크립트에 대한 솔루션 (?!=<groupname>)
에서는 그룹 내에 배치 하여 동일한 작업을 수행 할 수 있습니다 . 따라서 추가 괄호와 추가 !=
입니다. 꽤 비슷해!
모든 것을 문자열 프로토 타입 함수로 감쌌습니다.
풍모
명령
(?!={groupname})
이름을 지정하려는 각 그룹 내에 배치()
에 배치 하여 제거하십시오 ?:
. 이들은 이름이 지정되지 않습니다.arrays.js
// @@pattern - includes injections of (?!={groupname}) for each group
// @@returns - an object with a property for each group having the group's match as the value
String.prototype.matchWithGroups = function (pattern) {
var matches = this.match(pattern);
return pattern
// get the pattern as a string
.toString()
// suss out the groups
.match(/<(.+?)>/g)
// remove the braces
.map(function(group) {
return group.match(/<(.+)>/)[1];
})
// create an object with a property for each group having the group's match as the value
.reduce(function(acc, curr, index, arr) {
acc[curr] = matches[index + 1];
return acc;
}, {});
};
용법
function testRegGroups() {
var s = '123 Main St';
var pattern = /((?!=<house number>)\d+)\s((?!=<street name>)\w+)\s((?!=<street type>)\w+)/;
var o = s.matchWithGroups(pattern); // {'house number':"123", 'street name':"Main", 'street type':"St"}
var j = JSON.stringify(o);
var housenum = o['house number']; // 123
}
o의 결과
{
"house number": "123",
"street name": "Main",
"street type": "St"
}