RegExp.exec를 사용하여 문자열에서 모든 일치 항목을 추출하는 RegEx


175

다음과 같은 문자열을 구문 분석하려고합니다.

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

내부에 임의의 키 : "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"패턴과도 일치합니다. 모든 경기를 어떻게 되 찾을 수 있습니까?


정규식이 잘못되었거나 JavaScript의 정규식 기능을 잘못 사용하고있을 수 있습니다. 이것은 작동하는 것 같습니다 :> var s = "15는 15, 8은 8"; > var re = / \ d + / g; > var m = s.match (re); m = [ '15', '8']
틀린

6
Javascript에는 이제 .match () 함수가 있습니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 다음 과 같이 사용됩니다."some string".match(/regex/g)
Stefnotch

답변:


237

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/


8
while대신에 do … while?
Gumbo

15
while 루프를 사용하면 m을 초기화하기가 약간 어색합니다. 당신도 작성해야 while(m = re.exec(s))안티 패턴이 IMO 인, 또는 당신이 작성해야합니다 m = re.exec(s); while (m) { ... m = re.exec(s); }. 나는 do ... if ... while관용구를 선호 하지만 다른 기술도 효과가 있습니다.
lawnsea

14
크롬 에서이 작업을 수행하면 탭이 충돌했습니다.
EdgeCaseBerg

47
@EdgeCaseBerg g플래그를 설정 해야합니다 . 그렇지 않으면 내부 포인터가 앞으로 이동하지 않습니다. 문서 .
Tim

12
또 다른 요점은 정규 표현식이 빈 문자열과 일치 할 경우 무한 루프가된다는 것입니다
FabioCosta

139

str.match(pattern)pattern전역 플래그가있는 경우 g모든 일치 항목을 배열로 반환합니다.

예를 들면 다음과 같습니다.

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


15
주의 사항 : 일치하는 개체가 아니라 일치하는 문자열입니다. 예를 들어에있는 그룹에 액세스 할 수 없습니다. "All of us except @Emran:emran26, @Raju:raju13 and @Noman:noman42".match(/@(\w+):(\w+)/g)(반환 ["@Emran:emran26", "@Raju:raju13", "@Noman:noman42"])
madprog

4
@madprog, 맞습니다. 가장 쉬운 방법이지만 그룹 값이 필수적인 경우에는 적합하지 않습니다.
Anis

1
이것은 나를 위해 작동하지 않습니다. 나는 첫 번째 경기 만 얻는다.
Anthony Roberts

7
@AnthonyRoberts에 "g"플래그를 추가해야합니다. /@\w/g또는new RegExp("@\\w", "g")
Aruna Herath

88

모든 일치 항목을 반복하려면 다음 replace함수를 사용할 수 있습니다 .

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

s.replace(re, function(match, g1, g2) { console.log(g1, g2); });

너무 복잡하다고 생각합니다. 그러나 간단한 일을하는 다른 방법에 대해 아는 것이 좋습니다 (나는 당신의 대답을 찬성 투표했습니다).
Arashsoft

24
반 직관적 인 코드입니다. 의미있는 의미로 어떤 것도“대체”하지 않습니다. 다른 목적으로 일부 기능을 활용하고 있습니다.
Luke Maurer

6
@dudewad 만약 엔지니어들이 상자 밖에서 생각하지 않고 규칙을 따르고 있다면, 우리는 지금 다른 행성을 방문 할 생각조차하지 않을 것입니다. ;-)
Christophe

1
@dudewad 죄송합니다. 게으른 부분을 보지 못했습니다. 정확히 같은 방법을 "바꾸기"대신 "프로세스"라고한다면 문제가없는 것입니다. 나는 당신이 용어에 붙어있는 것이 두렵습니다.
Christophe

1
@Christophe 나는 분명히 용어에 붙어 있지 않습니다. 깨끗한 코드에 붙어 있습니다. 한 가지 목적을 위해 다른 목적으로 사용되는 것을 "해키"라고합니다. 이해하기 어렵고 종종 성능 측면에서 어려움을 겪지 않는 혼란스러운 코드를 만듭니다. OP가 정규식으로 처리하는 방법을 요구하기 때문에 정규 표현식 없이이 질문에 대답했다는 사실은 잘못된 답변이됩니다. 그러나이 커뮤니티를 높은 수준으로 유지하는 것이 중요하다는 것을 알았습니다. 그래서 제가 위에서 말한 것을 지키고 있습니다.
dudewad

56

이것은 해결책입니다

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

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

이것은 grasssea의 답변을 기반으로하지만 짧습니다.

호출 사이에서 내부 포인터를 앞으로 이동 시키려면`g '플래그를 설정해야합니다.


17
str.match(/regex/g)

모든 일치 항목을 배열로 반환합니다.

신비한 이유로 인해 exec이전 답변의 대안으로 추가 정보가 필요하다면 다음과 같이 루프 대신 재귀 함수로 수행 할 수 있습니다 (더 멋지다).

function findMatches(regex, str, matches = []) {
   const res = regex.exec(str)
   res && matches.push(res) && findMatches(regex, str, matches)
   return matches
}

// Usage
const matches = findMatches(/regex/g, str)

이전 의견에서 언급했듯이 g정규 표현식 정의 끝에 각 실행에서 포인터를 앞으로 이동시키는 것이 중요합니다 .


1
예. 재귀는 우아하고 시원하게 보입니다. 반복 루프는 간단하고 유지 관리 및 디버그가 더 쉽습니다.
Andy N

11

우리는 마침내 내장 matchAll함수 를보기 시작했습니다 . 설명 및 호환성 표는 여기를 참조 하십시오 . 2020 년 5 월 현재 Chrome, Edge, Firefox 및 Node.js (12+)는 지원되지만 IE, Safari 및 Opera는 지원되지 않습니다. 2018 년 12 월작성된 것처럼 보입니다. 모든 브라우저에 도달 할 시간을주지 만 거기에 도달 할 것이라고 믿습니다.

내장 matchAll함수는 iterable을 반환하기 때문에 좋습니다 . 또한 매 경기마다 캡처 그룹을 반환합니다! 그래서 당신은 같은 일을 할 수 있습니다

// get the letters before and after "o"
let matches = "stackoverflow".matchAll(/(\w)o(\w)/g);

for (match of matches) {
    console.log("letter before:" + match[1]);
    console.log("letter after:" + match[2]);
}

arrayOfAllMatches = [...matches]; // you can also turn the iterable into an array

모든 일치 객체가와 동일한 형식을 사용하는 것 같습니다 match(). 따라서 각 개체는 3 개의 추가 속성 indexinput, 및와 함께 일치 및 캡처 그룹의 배열입니다 groups. 따라서 다음과 같습니다.

[<match>, <group1>, <group2>, ..., index: <match offset>, input: <original string>, groups: <named capture groups>]

자세한 내용에 대해 matchAll도있다 구글 개발자 페이지 . 도 있습니다 polyfills / 심이 가능합니다.


나는 이것을 정말로 좋아하지만 Firefox 66.0.3에는 아직 도달하지 않았습니다. Caniuse 에는 아직 지원 목록이 없습니다. 나는 이것을 기대하고있다. Chromium 74.0.3729.108에서 작동하는 것으로 보입니다.
Lonnie Best

1
@LonnieBest 그래 , 내가 연결 한 MDN 페이지 의 호환성 섹션을 볼 수 있습니다 . Firefox가 버전 67에서 지원하기 시작한 것 같습니다. 제품을 배송하려는 경우 여전히 사용하지 않는 것이 좋습니다. 사용 가능한 폴리 필 / 심이 있습니다.이 답변에 추가했습니다
woojoo666

10

Agus의 함수를 기반으로하지만 일치 값만 반환하는 것이 좋습니다.

var bob = "&gt; bob &lt;";
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: [&gt;, &lt;]

8

이터 러블이 더 좋습니다 :

const matches = (text, pattern) => ({
  [Symbol.iterator]: function * () {
    const clone = new RegExp(pattern.source, pattern.flags);
    let match = null;
    do {
      match = clone.exec(text);
      if (match) {
        yield match;
      }
    } while (match);
  }
});

루프에서의 사용법 :

for (const match of matches('abcdefabcdef', /ab/g)) {
  console.log(match);
}

또는 배열을 원하는 경우 :

[ ...matches('abcdefabcdef', /ab/g) ]

1
오타 : if (m)이어야한다if (match)
Botje

배열은 이미 반복 가능하므로 일치하는 배열을 반환하는 모든 사람은 반복 가능을 반환합니다. 더 좋은 점은 브라우저가 실제로 내용을 인쇄 할 수있는 배열을 콘솔 로그에 기록하는 것입니다. 그러나 일반적인 iterable 콘솔 로깅은 [object Object] {...}를
가져옵니다.

모든 배열이 반복 가능하지만 모든 반복 가능 배열이 배열 인 것은 아닙니다. 발신자가 무엇을해야할지 모른다면 iterable이 우수합니다. 예를 들어, 첫 번째 일치를 원하면 iterable이 더 효율적입니다.
sdgfsdh

당신의 꿈은 현실이되고, 브라우저는 iterable을 반환하는 내장에matchAll 대한 지원을 시작 합니다 : D
woojoo666

1
이 답변 post-matchAll 구현을 보았습니다. 지원하는 브라우저 JS 용 코드를 작성했지만 실제로는 그렇지 않았습니다. 이것은 모두 동일하게 작동하므로 물건을 다시 쓰지 않아도됩니다-건배!
user37309

8

ES9가있는 경우

(시스템이 Chrome, Node.js, Firefox 등이 Ecmascript 2019 이상을 지원하는지 여부를 의미)

new를 사용하십시오 yourString.matchAll( /your-regex/ ).

ES9가없는 경우

구형 시스템을 사용하는 경우 쉽게 복사하고 붙여 넣을 수있는 기능이 있습니다.

function findAll(regexPattern, sourceString) {
    let output = []
    let match
    // make sure the pattern has the global flag
    let regexPatternWithGlobal = RegExp(regexPattern,"g")
    while (match = regexPatternWithGlobal.exec(sourceString)) {
        // get rid of the string copy
        delete match.input
        // store the match data
        output.push(match)
    } 
    return output
}

사용법 예 :

console.log(   findAll(/blah/g,'blah1 blah2')   ) 

출력 :

[ [ 'blah', index: 0 ], [ 'blah', index: 6 ] ]

5

다음은 일치하는 함수입니다.

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]);
});

이 솔루션은 전역 플래그 추가를 잊었을 때 무한 루프를 방지합니다.
user68311

2

ES9부터는 캡처 그룹 및 색인에 대한 정보와 함께 모든 일치 항목을 가져 오는 더 간단하고 더 나은 방법이 있습니다.

const string = 'Mice like to dice rice';
const regex = /.ice/gu;
for(const match of string.matchAll(regex)) {
    console.log(match);
}

// [ "마우스", 색인 : 0, 입력 : "쌀을 주사위처럼 쥐고있는 마우스", 그룹 : 정의되지 않음]

// [ "주사위", 색인 : 13, 입력 : "쌀을 죽이는 마우스", 그룹 : 정의되지 않음]

// [ "쌀", 색인 : 18, 입력 : "쌀을 죽이는 마우스", 그룹 : 정의되지 않음]

현재 Chrome, Firefox, Opera에서 지원됩니다. 이 내용을 읽는 시점에 따라 현재 지원을 보려면 이 링크 를 확인하십시오.


훌륭한! 그러나 정규 표현식에 플래그 glastIndex있어야하고를 호출하기 전에 0으로 재설정해야합니다 matchAll.
N. Kudryavtsev

1

이것을 사용하십시오 ...

var all_matches = your_string.match(re);
console.log(all_matches)

모든 일치하는 배열을 반환합니다 ... 그냥 잘 작동합니다 ....하지만 그룹을 고려하지는 않습니다 .. 전체 일치를 반환합니다 ...


0

String.match () 함수를 사용하고 관련 RegEx를 만드는 것이 좋습니다. 내 예제는 문자열 목록이 있으며 키워드와 문구에 대한 사용자 입력을 스캔 할 때 종종 필요합니다.

    // 1) Define keywords
    var keywords = ['apple', 'orange', 'banana'];

    // 2) Create regex, pass "i" for case-insensitive and "g" for global search
    regex = new RegExp("(" + keywords.join('|') + ")", "ig");
    => /(apple|orange|banana)/gi

    // 3) Match it against any string to get all matches 
    "Test string for ORANGE's or apples were mentioned".match(regex);
    => ["ORANGE", "apple"]

도움이 되었기를 바랍니다!


0

이것은 더 복잡한 문제를 해결하는 데 실제로 도움이되지는 않지만 귀하와 같은 글로벌 검색을 수행하지 않는 사람들을위한 간단한 솔루션이므로 어쨌든 게시하고 있습니다.

정답을 명확하게하기 위해 정규식을 단순화했습니다 (정확한 문제에 대한 해결책은 아닙니다).

var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);

// We only want the group matches in the array
function purify_regex(reResult){

  // Removes the Regex specific values and clones the array to prevent mutation
  let purifiedArray = [...reResult];

  // Removes the full match value at position 0
  purifiedArray.shift();

  // Returns a pure array without mutating the original regex result
  return purifiedArray;
}

// purifiedResult= ["description", "aoeu"]

그것은 의견 때문에보다 더 장황하게 보입니다. 이것은 의견이없는 것처럼 보입니다.

var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);

function purify_regex(reResult){
  let purifiedArray = [...reResult];
  purifiedArray.shift();
  return purifiedArray;
}

일치하지 않는 그룹은 배열에 다음과 같이 나열됩니다. undefined 값 됩니다.

이 솔루션은 ES6 스프레드 연산자를 사용하여 정규식 특정 값의 배열을 정제합니다. IE11을 지원하려면 Babel을 통해 코드를 실행해야합니다 .


0

여기 에 while 루프가없는 한 줄 솔루션이 있습니다.

순서는 결과 목록에 유지됩니다.

잠재적 단점은

  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 ] ]

0

여분의 공간이나 누락 된 공간과 같은 가장자리가있는 경우 경계가 적은이 표현식은 옵션 일 수 있습니다.

^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$

표현식을 탐색 / 단순화 / 수정하려는 경우 regex101.com의 오른쪽 상단에 설명되어 있습니다. 원하는 경우이 링크 에서 일부 샘플 입력과 어떻게 일치하는지 확인할 수도 있습니다.


테스트

const regex = /^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$/gm;
const str = `[description:"aoeu" uuid:"123sth"]
[description : "aoeu" uuid: "123sth"]
[ description : "aoeu" uuid: "123sth" ]
 [ description : "aoeu"   uuid : "123sth" ]
 [ description : "aoeu"uuid  : "123sth" ] `;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

정규식 회로

jex.im은 정규 표현식을 시각화합니다.

여기에 이미지 설명을 입력하십시오


-5

내 대답은 다음과 같습니다.

var str = '[me nombre es] : My name is. [Yo puedo] is the right word'; 

var reg = /\[(.*?)\]/g;

var a = str.match(reg);

a = a.toString().replace(/[\[\]]/g, "").split(','));

3
입력 문자열 ( str)의 형식이 잘못되었습니다 (너무 많은 대괄호). 값이 아닌 키만 캡처합니다. 코드에 구문 오류가 있으며 실행되지 않습니다 (마지막 괄호). 이미 받아 들여진 대답으로 "오래된"질문에 대답하는 경우 이미 받아 들여진 것보다 더 많은 지식과 더 나은 대답을 추가하십시오. 나는 당신의 대답이 그렇게 생각하지 않습니다.
삭제
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.