여러 반복 그룹을 캡처하는 방법은 무엇입니까?


87

동일한 패턴의 여러 그룹을 캡처해야합니다. 다음 문자열이 있다고 가정합니다.

HELLO,THERE,WORLD

그리고 다음 패턴을 작성했습니다.

^(?:([A-Z]+),?)+$

내가 원하는 것은 그룹 1이 "HELLO", 그룹 2는 "THERE", 그룹 3은 "WORLD"가되도록 모든 단어를 캡처하는 것입니다. 내 정규식이 실제로 마지막 하나만 캡처하는 " 세계".

여기에서 정규 표현식을 테스트 하고 있으며 Swift와 함께 사용하고 싶습니다 (스위프트에 어떻게 든 중간 결과를 얻을 수있는 방법이있을 수 있으므로 사용할 수 있습니까?)

업데이트 : 사용하고 싶지 않습니다 split. 이제 마지막 그룹뿐만 아니라 패턴과 일치하는 모든 그룹을 캡처하는 방법 만 있으면됩니다.


5
왜 분할하지 ,않습니까?
rock321987

사용 [A-Z]+하거나 [^,]+결과를 캡처 하지 않는 이유
rock321987

rock321987, 입력 문자열을 업데이트했습니다. 위의 패턴을 따르는 문자열을 정확히 추출해야합니다. 그리고 마지막 그룹뿐만 아니라 모든 그룹이 패턴과 일치하도록해야합니다. 정규식으로 수행하는 방법을 알고 싶습니다.
phbelov

2
rock321987, 무엇이 명확하지 않습니까? 일치하는 그룹이 되려면 문자열의 모든 단어가 필요하지만 내 패턴은 마지막 단어 ( "WORLD") 만 캡처합니다.
phbelov

1
모든 일치 항목을 찾으 려면이 답변 을 사용하세요.
rock321987

답변:


65

패턴에 하나의 그룹이 있으면 해당 그룹에서 정확한 결과를 하나만 얻을 수 있습니다. 캡처 그룹이 패턴에 의해 반복되는 경우 ( +주변 비 캡처 그룹 에서 수량자를 사용함 ) 일치하는 마지막 값만 저장됩니다.

패턴의 모든 일치 항목찾기 위해 언어의 정규식 구현 함수를 사용해야합니다 . 그런 다음 비 캡처 그룹의 앵커와 수량자를 제거해야합니다 (비 캡처 그룹 자체도 생략 할 수 있음).

또는 정규식을 확장하고 결과에서 얻고 자하는 그룹당 하나의 캡처 그룹을 패턴에 포함 시키십시오.

^([A-Z]+),([A-Z]+),([A-Z]+)$

17
다양한 수의 문자열을 설명하기 위해 어떻게 조정됩니까? 예 : HELLO, WORLD 및 HELLO, THERE, MY, WORLD. 두 예제를 모두 처리하고 더 긴 문자열 배열을위한 유연성이 내장 된 하나의 표현식을 찾고 있습니다
Chris

12
@Chris 일반화 할 수 없습니다. 대답에서 알 수 있듯이 캡처 그룹은 한 가지만 캡처 할 수 있으며 동적 캡처 그룹 수를 만들 수있는 방법이 없습니다.
Barmar

7

이런 게 필요한 것 같아요 ....

b="HELLO,THERE,WORLD"
re.findall('[\w]+',b)

Python3에서 반환되는

['HELLO', 'THERE', 'WORLD']

re.findall('\w+',b)2 자 더 짧습니다. 문자 클래스에 대한 필요가 당신은 하나 개의 표현이 없기 때문에
장 - 프랑수아 파브르

3

답변에 단락 2의 추가 예를 제공하기 위해. 한 그룹을 사용하여 세 경기를하는 것보다 한 경기에서 세 그룹을 얻는 것이 얼마나 중요한지 잘 모르겠습니다. 예 : 그루비에서 :

def subject = "HELLO,THERE,WORLD"
def pat = "([A-Z]+)"
def m = (subject =~ pat)
m.eachWithIndex{ g,i ->
  println "Match #$i: ${g[1]}"
}

Match #0: HELLO
Match #1: THERE
Match #2: WORLD

3

Byte Commander의 답변을 읽은 후 가능한 약간의 개선 사항을 소개하고 싶습니다.

미리 결정된 한 두 n단어 중 하나와 일치하는 정규 표현식을 생성 할 수 있습니다 n. 예를 들어 1 ~ 3 개의 단어를 일치 시키려면 정규 표현식 :

^([A-Z]+)(?:,([A-Z]+))?(?:,([A-Z]+))?$

다음 문장을 1 개, 2 개 또는 3 개의 캡처 그룹과 일치시킵니다.

HELLO,LITTLE,WORLD
HELLO,WORLD
HELLO

Regex101 에서이 정규식에 대한 자세한 설명을 볼 수 있습니다 .

내가 말했듯이 좋아하는 언어를 사용하여 원하는 그룹에 대해이 정규식을 생성하는 것은 매우 쉽습니다. 나는 빠른 사람이 아니기 때문에 다음은 루비 예제입니다.

def make_regexp(group_regexp, count: 3, delimiter: ",")
  regexp_str = "^(#{group_regexp})"
  (count - 1).times.each do
    regexp_str += "(?:#{delimiter}(#{group_regexp}))?"
  end
  regexp_str += "$"
  return regexp_str
end

puts make_regexp("[A-Z]+")

즉,이 경우 정규식을 사용하지 않는 것이 좋습니다 split. 필요에 따라 단순한 토큰 화 패턴에서 일부 토큰 화 패턴 까지 다른 많은 훌륭한 도구 가 있습니다. IMHO, 정규 표현식은 그중 하나가 아닙니다. 예를 들어 루비에서는 str.split(",")또는 같은 것을 사용합니다.str.scan(/[A-Z]+/)


2

주요 차이점은 반복 된 그룹캡처하는 대신 캡처 된 그룹을 반복하는 것입니다 .

이미 알고 있듯이 캡처 된 그룹을 반복하면 마지막 반복 만 캡처된다는 차이점이 있습니다. 반복 된 그룹을 캡처하면 모든 반복이 캡처됩니다.

PCRE (PHP) :

((?:\w+)+),?
Match 1, Group 1.    0-5      HELLO
Match 2, Group 1.    6-11     THERE
Match 3, Group 1.    12-20    BRUTALLY
Match 4, Group 1.    21-26    CRUEL
Match 5, Group 1.    27-32    WORLD

모든 캡처가 그룹 1에 있으므로 $1교체 만하면됩니다.

이 정규식의 다음과 같은 일반적인 형식을 사용했습니다.

((?:{{RE}})+)

regex101의


1

실제로 여러 번 일치하는 하나의 캡처 그룹이 있습니다. 여러 캡처 그룹이 아닙니다.

자바 스크립트 (js) 솔루션 :

let string = "HI,THERE,TOM";
let myRegexp = /([A-Z]+),?/g;       //modify as you like
let match = myRegexp.exec(string);  //js function, output described below
while(match!=null){                 //loops through matches
    console.log(match[1]);          //do whatever you want with each match
    match = myRegexp.exec(bob);     //find next match
}

산출:

HI
THERE
TOM

통사론:

// matched text: match[0]
// match start: match.index
// capturing group n: match[n]

보시다시피, 이것은 모든 경기에서 작동합니다.


0

내 대답이 늦었다는 것을 알고 있지만 오늘 나에게 발생하며 다음 접근 방식으로 해결했습니다.

^(([A-Z]+),)+([A-Z]+)$

따라서 첫 번째 그룹 (([A-Z]+),)+은 마지막 패턴 ([A-Z]+)과 일치하는 마지막 패턴을 제외한 모든 반복 패턴 과 일치합니다. 그리고 이것은 문자열에서 반복되는 그룹의 수에 관계없이 동적입니다.


3
이것은 문제에 대한 해결책이 아닙니다. 문제는 문자열을 일치시키는 것이 아니라 모든 그룹을 캡처하는 것입니다. 이 정규식은 여전히 ​​첫 번째 반복 그룹 (쉼표 사용)에 대한 마지막 일치와 마지막 그룹 (쉼표 제외)의 일치 만 캡처합니다.
gdwarf

0

죄송합니다. Swift가 아니라 가장 가까운 언어로 된 개념 증명입니다.

// JavaScript POC. Output:
// Matches:  ["GOODBYE","CRUEL","WORLD","IM","LEAVING","U","TODAY"]

let str = `GOODBYE,CRUEL,WORLD,IM,LEAVING,U,TODAY`
let matches = [];

function recurse(str, matches) {
    let regex = /^((,?([A-Z]+))+)$/gm
    let m
    while ((m = regex.exec(str)) !== null) {
        matches.unshift(m[3])
        return str.replace(m[2], '')
    }
    return "bzzt!"
}

while ((str = recurse(str, matches)) != "bzzt!") ;
console.log("Matches: ", JSON.stringify(matches))

참고 : 실제로 이것을 사용하려는 경우 문자열 바꾸기가 아니라 정규식 일치 함수에서 지정한 일치 위치를 사용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.