220

次の種類の文字列を解析しようとしています。

[key:"val" key2:"val2"]

内部には任意の key:"val" ペアがあります。キー名と値を取得したい。好奇心旺盛な人のために、私はタスク ウォリアーのデータベース形式を解析しようとしています。

ここに私のテスト文字列があります:

[description:"aoeu" uuid:"123sth"]

これは、スペース以外のキーまたは値に何でも含めることができること、コロンの周りにスペースを入れないこと、および値が常に二重引用符で囲まれていることを強調することを目的としています。

ノードでは、これは私の出力です:

[deuteronomy][gatlin][~]$ node
> var re = /^\[(?:(.+?):"(.+?)"\s*)+\]$/g
> re.exec('[description:"aoeu" uuid:"123sth"]');
[ '[description:"aoeu" uuid:"123sth"]',
  'uuid',
  '123sth',
  index: 0,
  input: '[description:"aoeu" uuid:"123sth"]' ]

しかしdescription:"aoeu"、このパターンにも一致します。すべての一致を取り戻すにはどうすればよいですか?

4

18 に答える 18

270

re.exec(s)ループ内で呼び出しを続けて、すべての一致を取得します。

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';
var m;

do {
    m = re.exec(s);
    if (m) {
        console.log(m[1], m[2]);
    }
} while (m);

この JSFiddle で試してみてください: https://jsfiddle.net/7yS2V/

于 2011-06-12T18:06:05.880 に答える
205

str.match(pattern)patternは、グローバル フラグを持っている場合、gすべての一致を配列として返します。

例えば:

const str = 'All of us except @Emran, @Raju and @Noman were there';
console.log(
  str.match(/@\w*/g)
);
// Will log ["@Emran", "@Raju", "@Noman"]

于 2017-04-25T22:35:45.847 に答える
97

すべての一致をループするには、次のreplace関数を使用できます。

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';

s.replace(re, function(match, g1, g2) { console.log(g1, g2); });
于 2012-07-12T01:35:19.030 に答える
61

これは解決策です

var s = '[description:"aoeu" uuid:"123sth"]';

var re = /\s*([^[:]+):\"([^"]+)"/g;
var m;
while (m = re.exec(s)) {
  console.log(m[1], m[2]);
}

これは Lawnsea の回答に基づいていますが、より短いです。

呼び出し間で内部ポインターを前方に移動するには、「g」フラグを設定する必要があることに注意してください。

于 2014-06-05T08:17:24.073 に答える
11

Agus の関数に基づいていますが、一致する値だけを返すことを好みます。

var bob = "> bob <";
function matchAll(str, regex) {
    var res = [];
    var m;
    if (regex.global) {
        while (m = regex.exec(str)) {
            res.push(m[1]);
        }
    } else {
        if (m = regex.exec(str)) {
            res.push(m[1]);
        }
    }
    return res;
}
var Amatch = matchAll(bob, /(&.*?;)/g);
console.log(Amatch);  // yeilds: [>, <]
于 2015-07-21T17:44:30.910 に答える
6

一致を取得するための私の関数は次のとおりです。

function getAllMatches(regex, text) {
    if (regex.constructor !== RegExp) {
        throw new Error('not RegExp');
    }

    var res = [];
    var match = null;

    if (regex.global) {
        while (match = regex.exec(text)) {
            res.push(match);
        }
    }
    else {
        if (match = regex.exec(text)) {
            res.push(match);
        }
    }

    return res;
}

// Example:

var regex = /abc|def|ghi/g;
var res = getAllMatches(regex, 'abcdefghi');

res.forEach(function (item) {
    console.log(item[0]);
});
于 2015-05-02T06:57:46.527 に答える
3

ここで使用できる場合は、次matchAllのトリックがあります。

Array.From「セレクター」パラメーターがあるため、厄介な「一致」結果の配列で終わる代わりに、本当に必要なものに投影できます。

Array.from(str.matchAll(regexp), m => m[0]);

グループに名前を付けた場合。( /(?<firstname>[a-z][A-Z]+)/g) あなたはこれを行うことができます:

Array.from(str.matchAll(regexp), m => m.groups.firstName);
于 2020-12-22T20:57:17.383 に答える
0

while loop を使用しない 1 行のソリューションを次に示します。

順序は結果のリストに保持されます。

潜在的な欠点は、

  1. 一致ごとに正規表現を複製します。
  2. 結果は、予想されるソリューションとは異なる形になります。もう一度処理する必要があります。
let re = /\s*([^[:]+):\"([^"]+)"/g
let str = '[description:"aoeu" uuid:"123sth"]'

(str.match(re) || []).map(e => RegExp(re.source, re.flags).exec(e))

[ [ 'description:"aoeu"',
    'description',
    'aoeu',
    index: 0,
    input: 'description:"aoeu"',
    groups: undefined ],
  [ ' uuid:"123sth"',
    'uuid',
    '123sth',
    index: 0,
    input: ' uuid:"123sth"',
    groups: undefined ] ]
于 2019-05-23T02:07:05.553 に答える