RegEx : 따옴표 사이의 값 잡기


답변:


361

나는 다음과 같이 큰 성공을 거두었습니다.

(["'])(?:(?=(\\?))\2.)*?\1

중첩 따옴표도 지원합니다.

이것이 어떻게 작동하는지에 대한 더 깊은 설명을 원하는 사람들을 위해 다음은 사용자 ephemient 의 설명입니다 .

([""'])따옴표와 일치; ((?=(\\?))\2.)백 슬래시가 존재한다면, 그것을 뒤섞 고, 그것이 발생하는지의 여부는 문자와 일치합니다. *?여러 번 일치시킵니다 (마지막 따옴표를 먹지 않기 위해 탐욕스럽지 않습니다). \1여는 데 사용 된 것과 동일한 견적을 찾습니다.


6
@ steve : 이것은 잘못 일치 "foo\"합니다. 미리보기 트릭은 ?수량자를 소유하게 만듭니다 (정규 풍미가 ?+구문 또는 원자 그룹화를 지원하지 않더라도 )
Robin

1
파이썬으로 다음과 같은 오류가 발생합니다. sre_constants.error : 열린 그룹을 참조 할 수 없습니다
a1an

9
일치하는 따옴표를 포함한 값을 반환합니다. 요청한대로 따옴표 사이내용 만 반환 할 기회가 없습니까?
Martin Schneider

4
예견을 소유 적 정량 자로 남용하는 것은 완전히 불필요하고 혼란 스럽다. (["'])(?:\\.|[^\\])*?\1
Aran-Fey

2
빈 문자열을 피하는 방법?
Vikas Bansal

333

일반적으로 다음 정규식 조각은 찾고 있습니다.

"(.*?)"

이것은 욕심없는 *를 사용합니까? 연산자는 다음 큰 따옴표를 포함하여 모든 것을 캡처합니다. 그런 다음 언어 별 메커니즘을 사용하여 일치하는 텍스트를 추출합니다.

파이썬에서는 다음을 수행 할 수 있습니다.

>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']

11
이 방법은 훌륭하지만 이스케이프 된 따옴표가있는 문자열은 처리하지 않습니다. 예 :"hello \" world"
robbyt

JavaScript의 일치를 사용하면 인용 부호도 일치합니다. 여기에 설명 된대로 exec를 반복해서 사용할 수 있습니다 : stackoverflow.com/questions/7998180/…
Kiechlus

4
@robbyt 답장이 늦었다는 것을 알고 있지만 부정적인 전망은 어떻습니까? "(.*?(?<!\\))"
Mateus

4
감사합니다. 처리 할 이스케이프 된 따옴표가없는 경우이 방법이 더 간단합니다.
squarecandy

한 단어. 대박 !
시바 아 불라

89

나는 갈 것이다 :

"([^"]*)"

[^ "] 를 제외한 모든 문자에 대한 정규식입니다 ' " '
나는 비 욕심 많은 조작을 통해이를 사용하는 이유는 그냥 확실히 나는 그것이 해결받을 수 있도록 그를 계속 찾고해야한다는 것입니다.


1
이것은 다른 정규 표현식 해석에서도 잘 작동합니다.
Phil Bennett

5
이것은 나의 정신을 구했다. .NET의 RegEx 구현에서 "(. *?)"는 원하는 효과를 갖지 않지만 (그런 욕심을 일으키지 않습니다) "([^"] *) "
Jens Neubauer

이것이 가장 좋은 답변입니다. 감사합니다
Lmao 123

28

이스케이프 된 따옴표를 처리하는 두 가지 효율적인 방법을 살펴 보겠습니다. 이러한 패턴은 간결하거나 미학적으로 설계된 것이 아니라 효율적으로 설계되었습니다.

이러한 방법은 첫 번째 문자 구분을 사용하여 대체 비용없이 문자열에서 따옴표를 빠르게 찾습니다. (이 아이디어는 대체의 두 가지를 테스트하지 않고 따옴표가 아닌 문자를 빨리 버리는 것입니다.)

따옴표 사이의 내용은 반복되는 교체 대신 언롤 된 루프로 설명되어 더욱 효율적입니다. [^"\\]*(?:\\.[^"\\]*)*

따옴표가 균형이 맞지 않는 문자열을 처리하려면 분명히 [^"\\]*+(?:\\.[^"\\]*)*+역 추적을 피하기 위해 소유 수량 자를 사용하거나이를 에뮬레이트하는 해결 방법을 사용할 수 있습니다 . 이스케이프 처리되지 않은 다음 인용 또는 문자열 끝까지 인용 된 부분이 시작 인용이 될 수 있도록 선택할 수도 있습니다. 이 경우 소유 수량자를 사용할 필요가 없으며 마지막 따옴표 만 선택하면됩니다.

주의 : 때때로 따옴표는 백 슬래시로 이스케이프되지 않고 따옴표를 반복하여 이스케이프됩니다. 이 경우 컨텐츠 서브 패턴은 다음과 같습니다.[^"]*(?:""[^"]*)*

패턴은 캡처 그룹과 역 참조 ( (["']).....\1)같은 것을 피하고 간단한 교대를 사용하지만 ["']시작 부분 과 함께 사용합니다 .

펄 같은 :

["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')

( (?s:...)캡처하지 않은 그룹 내에서 dotall / singleline 모드를 켜는 구문 설탕입니다.이 구문이 지원되지 않는 경우 모든 패턴에 대해이 모드를 쉽게 켜거나 점을로 바꿀 수 있습니다 [\s\S])

(이 패턴이 작성되는 방식은 완전히 "수동식"이며 최종 엔진 내부 최적화를 고려하지 않습니다)

ECMA 스크립트 :

(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')

POSIX 확장 :

"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'

또는 간단히 :

"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'

1
파이썬은 원시 문자열 형식의 ECMA 스크립트를 받아들입니다. 예 : r "" "ECMA 스크립트" ""
a1an

1
이것은 훌륭합니다. 큰 따옴표 안에 줄 바꿈 및 캐리지 리턴을 사용하여 ECMA를 조정하는 것이 매우 쉽습니다.
Douglas Gaskell

@ douglasg14b : 감사합니다. 참고 당신은 자바 스크립트를 사용하려는 경우, 당신은 단지 문자 표기법을 사용하는 데 필요한 /pattern/(대신 객체 표기법의 아무것도 탈출하지 않고 new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");)
카시미르 등 히폴리토스를

@ a1an : 그렇습니다. 그러나 s여기 를 제거 하고 패턴 어딘가에 (?s:놓으면 Perl 버전을 사용할 수 있습니다 (?s).
Casimir et Hippolyte

16

: 허용 대답의 정규식은 자신을 sourrounding 인용 부호를 포함하여 값을 반환 "Foo Bar"하고 "Another Value"일치로합니다.

다음은 질문자가 요구 한대로 따옴표 사이값만 반환하는 RegEx입니다 .

큰 따옴표 만 (캡처 그룹 # 1의 값 사용) :

"(.*?[^\\])"

작은 따옴표 만 (캡처 그룹 # 1의 값 사용) :

'(.*?[^\\])'

둘 다 (캡처 그룹 # 2의 값 사용) :

(["'])(.*?[^\\])\1

-

모든 지원 이스케이프 및 중첩 따옴표.


왜 이것이 효과가 있습니까? 나는 사용하고 src="(.*)"있었지만 분명히 마지막 "전에 모든 것을 선택하고 있었지만, REGEX는 src =" "내용 만 선택했지만 어떻게 이해하지 못했습니까?
Lucas Bustamante

나는 이것이 단순하기 때문에 이것을 많이 좋아하지만 내가 발견 한 것처럼 따옴표 사이의 값이 비어 있거나 값을 처리하지 않습니다.
RedactedProfile

16

특히,이 답변 중 어느 것도 반환 된 일치하는 따옴표 안의 텍스트 인 정규 표현식을 생성하지 않습니다. MA- 매든은 전체 경기가 아닌 캡처 된 그룹으로 내부 경기 만 시도합니다. 실제로 수행하는 한 가지 방법은 다음과 같습니다.

(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)

이에 대한 예제는이 데모에서 볼 수 있습니다 https://regex101.com/r/Hbj8aP/1

여기서 핵심은 시작 부분 ?<=의 긍정적 인 전망 ( )과 끝 부분의 긍정적 인 전망 ( ?=)입니다. lookbehind는 현재 문자 뒤에서 따옴표를 확인하기 위해 찾고 있습니다. 발견 된 경우 거기에서 시작한 다음 lookahead는 따옴표를 위해 앞의 문자를 확인하고 발견되면 해당 문자를 중지합니다. lookbehind 그룹 ( ["'])은 괄호로 묶어 시작시 따옴표가 발견 된 그룹을 작성하며, 마지막 룩어 헤드 (?=\1)에서 해당 따옴표를 찾을 때만 중지되도록 사용됩니다.

다른 복잡한 문제는 lookahead가 실제로 작은 따옴표를 사용하지 않기 때문에 시작 lookbehind에 의해 다시 발견되어 같은 줄의 끝과 시작 따옴표 사이의 텍스트가 일치한다는 것입니다. 여는 인용 부호 ( ["']\b) 에 단어 경계를 두는 것이 이상적이지만 미리보기를 지나고 싶지만 그럴 수는 없다고 생각합니다. 내가 아담의 대답에서 직접 가져온 중간에 이스케이프 문자를 허용하는 비트.



8

(["'])(?:(?=(\\?))\2.)*?\1위 의 패턴 은 작업을 수행하지만 성능이 걱정됩니다 (나쁘지는 않지만 더 나을 수 있음). ~ 20 % 더 빠릅니다.

패턴 "(.*?)"이 불완전합니다. 이것을 읽는 모든 사람들을위한 나의 충고는 단지 IT를 사용하지 않는 것입니다 !!!

예를 들어 아래 문자열과 같이 많은 문자열을 캡처 할 수 없습니다 (필요한 경우 철저한 테스트 사례를 제공 할 수 있음).

$ string = '어떻게 지내? 나는 \''감사합니다, 벌금을 해요;

나머지는 위와 마찬가지로 "좋다".

성능과 정밀도를 모두 중요하게 생각한다면 다음 중 하나로 시작하십시오.

/(['"])((\\\1|.)*?)\1/gm

내 테스트에서 그것은 내가 만난 모든 문자열을 다루었지만 작동하지 않는 것을 발견하면 기꺼이 업데이트 할 것입니다.

온라인 정규식 테스터에서 내 패턴을 확인하십시오 .


1
나는 당신의 패턴의 단순함을 좋아하지만, 성능면에서 Casimir et Hippolyte의 패턴은 모든 확장 된 솔루션을 물 밖으로 날려 버립니다. 또한 패턴 끝에 문장 끝 이스케이프 된 인용 부호와 같은 확장 된 대소 문자에 문제가있는 것 같습니다.
wp78de

7

나는 인용 부호를 피하면서 인용 부호 사이의 내용을 일치시키는 Eugen Mihailescu의 솔루션 을 좋아했습니다 . 그러나 탈출에 문제가 있음을 발견하고 다음 정규식을 수정했습니다.

(['"])(?:(?!\1|\\).|\\.)*\1

그것은 트릭을 수행하고 여전히 간단하고 유지 보수가 쉽습니다.

데모 (테스트 사례가 더 많으 므로 자유롭게 사용하고 확장하십시오).


추신 : 전체 일치 ( ) 의 인용 부호 사이 에 내용 $0을 원하고 성능 패널티 사용을 두려워하지 않는 경우 :

(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)

불행히도 앵커로 인용 부호 \b가 없으면 시작 인용 후 공백과 단어가 아닌 경계 문자와 잘 어울리지 않는 경계를 추가해야했습니다 .

또는 단순히 그룹을$2 추가 하고 문자열 형식을 추출 하여 초기 버전을 수정하십시오 .

(['"])((?:(?!\1|\\).|\\.)*)\1

PPS : 효율성에만 초점을 둔 경우 Casimir et Hippolyte의 솔루션으로 이동하십시오 . 좋은 것입니다.


관찰 : 두 번째 정규 표현식 -은 경도 좌표와 같이 빼기 부호가있는 값을 누락합니다 .
크로우 코더

나는 아무것도 바꾸지 않았다. 문제를 관찰하지 않으면 아마도 내가 사용하고있는 정규식의 풍미 일 것입니다. 나는 regex101site를 사용하고 있었고 PHP 스타일의 정규식이라고 생각합니다.
Crowcoder

여기 내가 말하는 것에 대한 데모가 있습니다. 경도 (-96.74025)와 일치 할 것으로 예상했지만 일치하지 않습니다.
Crowcoder

@Crowcoder 감사합니다. 예, 이것은 앵커 역할을하는 단어 경계로 인해 발생하며 일치하는 항목은 겹치지 않지만 입력 내용에는 적합하지 않습니다. 업데이트 된 답변에 명시된 바와 같이 실제로 추가 그룹이 더 나은 옵션입니다.
wp78de

6

이 버전

  • 이스케이프 된 따옴표를 설명합니다
  • 역 추적 제어

    /(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/

이것은 여러 문자열에 걸쳐 있으며 이중 백 슬래시를 올바르게 처리하지 않는 것 같습니다 (예 : foo 'stri \\ ng 1'bar
miracle2k

문자 클래스에는 역 참조를 사용할 수 없습니다.
HamZa

5

더 많은 답변! 여기 내가 사용한 솔루션이 있습니다.

\"([^\"]*?icon[^\"]*?)\"

TLDR;
단어 아이콘 을 당신이 말한 따옴표와 짜잔에서 찾고있는 것으로 바꾸십시오 !


이것이 작동하는 방식은 키워드를 찾고 따옴표 사이의 다른 것을 신경 쓰지 않는 것입니다. EG :
id="fb-icon"
id="icon-close"
id="large-icon-close"
정규 표현식은 따옴표를 "
찾은 다음 "
찾을 때까지는 사용할 수 없는 문자 그룹을 찾고 icon
그렇지 않은 문자는 그룹 "
을 찾습니다."


1
대단히 감사합니다. 발생할 때마다 대체 할 수 있었다 name="value"과를 name={"value"}이 답변의 정규식 반환 이후 icon/ value(허용 대답과는 달리) 두 번째 그룹으로. 찾기 : =\"([^\"]*?[^\"]*?)\" 바꾸기 :={"$1"}
Palisand

downvote를 설명하는 마음? 어떤 상황에서는 잘 작동합니다.
제임스 해링턴

답장을 하시겠습니까?
Palisand

@Palisand 다른 사람은 설명없이 아무 것도이 게시물에 투표하지 않았습니다.
제임스 해링턴

이것은 인용 부호 안에 특정 텍스트를 찾는 유일한 해답 인 것 같습니다
Top-Master

4

나는 Axeman의 더 광범위한 버전을 좋아했지만 문제가있었습니다 (예를 들어 일치하지 않았습니다)

foo "string \\ string" bar

또는

foo "string1"   bar   "string2"

올바르게 수정했습니다.

# opening quote
(["'])
   (
     # repeat (non-greedy, so we don't span multiple strings)
     (?:
       # anything, except not the opening quote, and not 
       # a backslash, which are handled separately.
       (?!\1)[^\\]
       |
       # consume any double backslash (unnecessary?)
       (?:\\\\)*       
       |
       # Allow backslash to escape characters
       \\.
     )*?
   )
# same character as opening quote
\1

3
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)

그냥 사용해보십시오, 매력처럼 작동합니다!

\ 스킵 문자를 나타냅니다


첫 번째 줄이 실제 파이썬 코드라면 string을 만들 것 " foo bar" "loloo"입니다. 나는 당신이 정규 표현식으로했던 것처럼 원시 문자열로 그것을 감싸려고했다고 생각합니다 r'"\" foo bar\" \"loloo\""'. 필요할 때마다 SO의 뛰어난 서식 기능 을 사용하십시오 . 화장품 만이 아닙니다. 우리는 당신이 그들을 사용하지 않으면 말하려는 것을 말할 수 없습니다. 그리고 스택 오버플로에 오신 것을 환영합니다 !
Alan Moore

조언 앨런에 감사드립니다, 나는 실제로이 커뮤니티를 처음 사용합니다.
mobman

2

Adam의 답변과 달리 간단하지만 효과가 있습니다.

(["'])(?:\\\1|.)*?\1

다음과 같이 따옴표로 내용을 가져 오려면 괄호를 추가하십시오.

(["'])((?:\\\1|.)*?)\1

그런 다음 $1quote char과 $2일치하고 content 문자열 과 일치합니다.


1
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'

결과는 다음과 같습니다 :> Foo Bar <> <> 그러나 이것 <

여기서는 명확성을 위해> < 's 사이의 결과 문자열을 보여 주었으며,이 sed 명령으로 탐욕스럽지 않은 버전을 사용하여 먼저 ""와 그 이후의 정크를 버린 다음 ""사이의 부분으로 대체합니다. > < 's로 둘러 쌉니다.


1

Greg H.로부터 나는이 정규식을 내 필요에 맞게 만들 수있었습니다.

따옴표 안에 들어서 특정 값과 일치해야했습니다. 전체 일치해야하며 부분 일치는 적중을 유발할 수 없습니다.

예를 들어 "test"는 "test2"와 일치 할 수 없습니다.

reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
    print "winning..."

사냥꾼


1

도트 구문과 같이 특정 접미사 만있는 문자열을 찾으려면 다음을 시도하십시오.

\"([^\"]*?[^\"]*?)\".localized

.localized접미사는 어디에 있습니까 ?

예:

print("this is something I need to return".localized + "so is this".localized + "but this is not")

그것은 캡처 "this is something I need to return".localized하고 "so is this".localized있지만 "but this is not".


1

Microsoft VBA 코더 의 하위 집합에 대한 보충 답변 은 라이브러리 Microsoft VBScript Regular Expressions 5.5를 사용하며 다음 코드를 제공합니다.

Sub TestRegularExpression()

    Dim oRE As VBScript_RegExp_55.RegExp    '* Tools->References: Microsoft VBScript Regular Expressions 5.5
    Set oRE = New VBScript_RegExp_55.RegExp

    oRE.Pattern = """([^""]*)"""


    oRE.Global = True

    Dim sTest As String
    sTest = """Foo Bar"" ""Another Value"" something else"

    Debug.Assert oRE.test(sTest)

    Dim oMatchCol As VBScript_RegExp_55.MatchCollection
    Set oMatchCol = oRE.Execute(sTest)
    Debug.Assert oMatchCol.Count = 2

    Dim oMatch As Match
    For Each oMatch In oMatchCol
        Debug.Print oMatch.SubMatches(0)

    Next oMatch

End Sub

0

나를 위해이 일을했습니다.

|([\'"])(.*?)\1|i

나는 다음과 같은 문장에서 사용했습니다.

preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);

그리고 그것은 잘 작동했습니다.


이 방법의 약점은 문자열이 작은 따옴표로 시작하고 큰 따옴표로 끝나거나 그 반대의 경우에도 일치한다는 것입니다.
Ghopper21

또한 "@를 잊지 마십시오"- "Don"다음에 중지됩니다.
Benny Neugebauer 2012 년

0

위의 모든 대답은 훌륭합니다 .... 모든 유니 코드 문자를 지원하지는 않습니다. ECMA 스크립트 (자바 스크립트)

Node 사용자 인 경우 모든 유니 코드 문자를 지원하는 수정 된 버전의 허용 된 응답을 원할 수 있습니다.

/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu

여기를 보십시오 .


1
비 유니 코드 문자는 무엇입니까? AFAIK 유니 코드는 모든 문자를 포함 합니다 .
토토

1
왜 이것이 자바 스크립트 질문이라고 생각합니까? 또한 lookbehind가 모든 브라우저에서 지원되는 것은 아니며, regex101이 발생합니다? The preceding token is not quantifiable
Toto

@Toto, 내 말은 "모든 유니 코드 문자를 지원하지는 않는다"는 것입니다. 감사합니다. 질문은 일반적으로 정규 표현식에 관한 것이지만 단어 경계 어설 션을 사용하면 Javascript에서 원하지 않는 동작이 발생할 수 있음을 강조하고 싶지 않습니다. 물론 자바 스크립트는 일반적으로 브라우저 용이지만 Node도 있습니다.
Donovan P
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.