私の知る限りでは、JavaScriptの名前付きキャプチャグループなどはありません。同様の機能を取得する別の方法は何ですか?
私の知る限りでは、JavaScriptの名前付きキャプチャグループなどはありません。同様の機能を取得する別の方法は何ですか?
回答:
ECMAScript 2018では、名前付きキャプチャグループをJavaScript正規表現に導入しています。
例:
const auth = 'Bearer AUTHORIZATION_TOKEN'
const { groups: { token } } = /Bearer (?<token>[^ $]*)/.exec(auth)
console.log(token) // "Prints AUTHORIZATION_TOKEN"
古いブラウザをサポートする必要がある場合は、名前付きキャプチャグループで実行できる通常の(番号付き)キャプチャグループですべてを実行できます。番号を追跡するだけで済みます。これは、キャプチャグループの順序が正規表現の変更。
私が考えることができる名前付きキャプチャグループの2つの「構造的」利点のみがあります。
一部の正規表現フレーバー(私が知る限り、.NETおよびJGSoft)では、正規表現の異なるグループに同じ名前を使用できます(これが重要な例については、こちらを参照してください)。しかし、ほとんどの正規表現フレーバーは、とにかくこの機能をサポートしていません。
数字で囲まれている状況で番号付きのキャプチャグループを参照する必要がある場合は、問題が発生する可能性があります。あなたが数字にゼロを追加したいので、交換したいとしましょう(\d)
と$10
。JavaScriptではこれが機能します(正規表現のキャプチャグループが10未満の場合)。ただし、Perlは数値では10
なく後方参照番号を探し1
、その後に0
。Perlでは${1}0
、この場合に使用できます。
それ以外では、名前付きのキャプチャグループは単なる「構文上の砂糖」です。本当に必要な場合にのみキャプチャグループを使用し、非キャプチャグループを使用すると役立ちます(?:...)
し、他のすべての状況で。
JavaScriptに関する(私の意見では)より大きな問題は、JavaScriptが冗長な正規表現をサポートしていないため、読みやすく複雑な正規表現を簡単に作成できることです。
Steve LevithanのXRegExpライブラリはこれらの問題を解決します。
追加の構文、フラグ、およびメソッドのサポートを含む、正規表現の拡張された拡張可能なクロスブラウザー実装であるXRegExpを使用できます。
s
、ドットをすべての文字に一致させる(別名dotallまたはシングルラインモード)、およびx
、フリースペースおよびコメント(別名拡張モード)に追加します。ES6では、配列分解を使用してグループをキャッチできます。
let text = '27 months';
let regex = /(\d+)\s*(days?|months?|years?)/;
let [, count, unit] = regex.exec(text) || [];
// count === '27'
// unit === 'months'
通知:
let
は、結果の配列の最初の値をスキップします。これは、一致した文字列全体です。|| []
後は、.exec()
一致がないとき(ので、非構造エラーを防ぐことができます.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の文法に従う必要があります。
名前付きグループには、正規表現結果のgroupsプロパティのプロパティからアクセスできます。名前のないグループと同様に、グループへの番号付き参照も作成されます。例えば:
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'));
named-regexpという node.jsライブラリがあります。node.jsプロジェクトで使用できるます(ブラウザで、browserifyまたは他のパッケージスクリプトを使用してライブラリをパッケージ化します)。ただし、ライブラリは、名前のないキャプチャグループを含む正規表現では使用できません。
正規表現で開始キャプチャ中括弧を数える場合、名前付きキャプチャグループと正規表現の番号付きキャプチャグループ間のマッピングを作成でき、自由に組み合わせて一致させることができます。正規表現を使用する前に、グループ名を削除する必要があります。それを示す3つの関数を作成しました。この要旨を参照してください:https : //gist.github.com/gbirke/2cc2370135b665eee3ef
ティムPietzckerは、 JavaScriptの正規表現にグループを取り込むという名前の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>
バニラJavaScriptではこれを行うことはできませんが、何らかのマジックを使用して、インデックス付きの一致を名前付きの一致に変換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>
では、グループ内に配置して名前付きグループを示すことができますが、私の古いJavaScriptのソリューションで(?!=<groupname>)
は、グループ内に配置して同じことを行うことができます。つまり、括弧の追加セットと追加の!=
です。非常に近いです!
すべてを文字列プロトタイプ関数にラップしました
特徴
指示
(?!={groupname})
の名前にしたい各グループ内()
置くことによって、非キャプチャグループを削除することを忘れないでください?:
。これらは名前が付けられません。array.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"
}