두 마커 사이의 부분 문자열을 추출하는 방법은 무엇입니까?


335

문자열이 'gfgfdAAA1234ZZZuijjk'있고 '1234'일부만 추출하고 싶다고 가정 해 봅시다 .

나는 단지 몇 개의 문자가 무엇인지 AAA, 그리고 ZZZ내가 관심을 갖고있는 부분 이후에 무엇이 될지 알고 있습니다 1234.

sed그 문자열과 같은 것을 할 수 있습니다 :

echo "$STRING" | sed -e "s|.*AAA\(.*\)ZZZ.*|\1|"

그리고 이것은 1234결과적으로 나를 줄 것 입니다.

파이썬에서 같은 일을하는 방법?

답변:


588

정규 표현식 사용- 추가 참조를위한 문서

import re

text = 'gfgfdAAA1234ZZZuijjk'

m = re.search('AAA(.+?)ZZZ', text)
if m:
    found = m.group(1)

# found: 1234

또는:

import re

text = 'gfgfdAAA1234ZZZuijjk'

try:
    found = re.search('AAA(.+?)ZZZ', text).group(1)
except AttributeError:
    # AAA, ZZZ not found in the original string
    found = '' # apply your error handling

# found: 1234

20
두 번째 해결책은 패턴이 대부분 일치하면 허가보다 용서를 구하기 쉽기 때문에 더 좋습니다. .
Bengt

7
인덱싱이 0에서 시작하지 않습니까? 따라서 group (1) 대신 group (0)을 사용해야합니까?
Alexander

22
@Alexander, no, group (0)은 전체 일치 문자열 AAA1234ZZZ를 반환하고 group (1)은 첫 번째 그룹과 일치하는 문자 만 반환합니다. 1234
Yurii K

1
@Bengt : 왜 그렇습니까? 첫 번째 솔루션은 나에게 매우 단순 해 보이며 코드 줄이 적습니다.
안녕 안녕

5
이 표현에서? +를 욕심이 없도록 수정합니다. 1 이상에서 여러 번 일치하지만 가능한 한 적게 필요한만큼만 확장됩니다. ?가 없으면 첫 번째 그룹은 gfgfAAA2ZZZkeAAA43ZZZonife를 2ZZZkeAAA43과 일치하지만? 그것은 단지 2와 일치 할 것이고, 복수를 검색하는 것 (또는 그것을 제거하고 다시 검색하는 것)은 43과 일치 할 것입니다.
Dom

114
>>> s = 'gfgfdAAA1234ZZZuijjk'
>>> start = s.find('AAA') + 3
>>> end = s.find('ZZZ', start)
>>> s[start:end]
'1234'

그런 다음 원하는 경우 re 모듈과 함께 정규 표현식을 사용할 수도 있지만 필요하지 않습니다.


9
질문은 입력 텍스트가 항상 "AAA"와 "ZZZ"를 모두 포함한다는 것을 암시하는 것 같습니다. 그렇지 않은 경우 대답이 끔찍하게 실패합니다 (빈 문자열이나 예외를 던지는 대신 완전히 잘못된 것을 반환한다는 것을 의미합니다. "hello there"를 입력 문자열로 생각하십시오).
tzot

@ user225312 re방법이 빠르지 않습니까?
confused00

1
투표하지만 유지 관리를 위해 "s.find ( 'AAA') + 3"대신 "x = 'AAA'; s.find (x) + len (x)"를 사용합니다.
Alex

1
토큰의가에서 찾을 수없는 경우 s, s.find반환합니다 -1. 슬라이싱 연산자 s[begin:end] 는이를 유효한 인덱스로 받아들이고 원하지 않는 부분 문자열을 반환합니다.
ribamar


65

정규식

import re

re.search(r"(?<=AAA).*?(?=ZZZ)", your_text).group(0)

위에있는 AttributeError"AAA"및 "ZZZ"가 없으면 위와 같이 실패합니다 .your_text

문자열 메소드

your_text.partition("AAA")[2].partition("ZZZ")[0]

"AAA"또는 "ZZZ"가 존재하지 않으면 위의 문자열은 빈 문자열을 반환합니다 your_text.

PS Python Challenge?


6
이 답변은 아마도 더 많은 표를받을 가치가 있습니다. 문자열 방법이 가장 강력한 방법입니다. 시도 / 제외가 필요하지 않습니다.
ChaimG

... 제한적이지만 훌륭합니다. 파티션은 정규 표현식을 기반으로하지 않으므로 검색 문자열이 고정 리터럴로 묶여 있기 때문에이 인스턴스에서만 작동합니다.
GreenAsJade

큰 감사합니다! -이것은 문자열에 적용되며 정규 표현식이 필요하지 않습니다
Alex

15
import re
print re.search('AAA(.*?)ZZZ', 'gfgfdAAA1234ZZZuijjk').group(1)

1
AttributeError: 'NoneType' object has no attribute 'groups'-현에 AAA, ZZZ가 없다면 ...
eumiro

12

일회성 스크립트를위한 나의 빠른 버전 인 이것을 아무도 언급하지 않은 것에 놀랐다 :

>>> x = 'gfgfdAAA1234ZZZuijjk'
>>> x.split('AAA')[1].split('ZZZ')[0]
'1234'

@ user1810100은 기본적으로이 글을 게시하기 전까지 거의 정확히 5 년이 지난 것을 언급했습니다.
John

10

한 줄의 코드 만 사용하면됩니다.

>>> import re

>>> re.findall(r'\d{1,5}','gfgfdAAA1234ZZZuijjk')

>>> ['1234']

결과는 목록을받습니다 ...


7

이를 위해 re 모듈을 사용할 수 있습니다 .

>>> import re
>>> re.compile(".*AAA(.*)ZZZ.*").match("gfgfdAAA1234ZZZuijjk").groups()
('1234,)

5

sed를 사용하면 문자열로 다음과 같은 작업을 수행 할 수 있습니다.

echo "$STRING" | sed -e "s|.*AAA\(.*\)ZZZ.*|\1|"

그리고 이것은 결과적으로 1234를 줄 것입니다.

re.sub동일한 정규 표현식을 사용하여 함수로 동일한 작업을 수행 할 수 있습니다.

>>> re.sub(r'.*AAA(.*)ZZZ.*', r'\1', 'gfgfdAAA1234ZZZuijjk')
'1234'

기본 sed에서 캡처 그룹은로 표시 \(..\)되지만 Python에서는로 표시됩니다 (..).


5

파이썬에서는 findall정규 표현식 ( re) 모듈의 메소드를 사용하여 하위 문자열 양식 문자열을 추출 할 수 있습니다 .

>>> import re
>>> s = 'gfgfdAAA1234ZZZuijjk'
>>> ss = re.findall('AAA(.+)ZZZ', s)
>>> print ss
['1234']

4

코드에서이 함수를 사용하여 첫 번째 부분 문자열을 찾을 수 있습니다 (문자 색인 기준). 또한 부분 문자열 뒤의 내용을 찾을 수 있습니다.

def FindSubString(strText, strSubString, Offset=None):
    try:
        Start = strText.find(strSubString)
        if Start == -1:
            return -1 # Not Found
        else:
            if Offset == None:
                Result = strText[Start+len(strSubString):]
            elif Offset == 0:
                return Start
            else:
                AfterSubString = Start+len(strSubString)
                Result = strText[AfterSubString:AfterSubString + int(Offset)]
            return Result
    except:
        return -1

# Example:

Text = "Thanks for contributing an answer to Stack Overflow!"
subText = "to"

print("Start of first substring in a text:")
start = FindSubString(Text, subText, 0)
print(start); print("")

print("Exact substring in a text:")
print(Text[start:start+len(subText)]); print("")

print("What is after substring \"%s\"?" %(subText))
print(FindSubString(Text, subText))

# Your answer:

Text = "gfgfdAAA1234ZZZuijjk"
subText1 = "AAA"
subText2 = "ZZZ"

AfterText1 = FindSubString(Text, subText1, 0) + len(subText1)
BeforText2 = FindSubString(Text, subText2, 0) 

print("\nYour answer:\n%s" %(Text[AfterText1:BeforText2]))

3
>>> s = '/tmp/10508.constantstring'
>>> s.split('/tmp/')[1].split('constantstring')[0].strip('.')

3
text = 'I want to find a string between two substrings'
left = 'find a '
right = 'between two'

print(text[text.index(left)+len(left):text.index(right)])

준다

string

2

누군가가 내가했던 것과 똑같은 일을해야 할 경우를 대비하여. 괄호 안의 모든 것을 한 줄로 추출해야했습니다. 예를 들어, '미국 대통령 (Barack Obama)과 만난 ...'과 같은 줄이 있고 'Barack Obama'만 얻으려면 이것이 해결책입니다.

regex = '.*\((.*?)\).*'
matches = re.search(regex, line)
line = matches.group(1) + '\n'

즉, 괄호를 차단해야합니다. slash \ 부호가있는 . 파이썬보다 더 정규 표현식에 대한 문제이지만.

또한 어떤 경우에는 정규식 정의 전에 'r'기호가 표시 될 수 있습니다. r 접두사가 없으면 C와 같이 이스케이프 문자를 사용해야 합니다. 이에 대한 자세한 내용은 다음과 같습니다 .


2

PyParsing 사용

import pyparsing as pp

word = pp.Word(pp.alphanums)

s = 'gfgfdAAA1234ZZZuijjk'
rule = pp.nestedExpr('AAA', 'ZZZ')
for match in rule.searchString(s):
    print(match)

결과는 다음과 같습니다.

[['1234']]


0

다음은 첫 번째 하위 문자열에 두 번째 하위 문자열이 포함 된 시나리오를 설명하는 정규 표현식이없는 솔루션입니다. 이 함수는 두 번째 마커가 첫 번째 마커 뒤에있는 경우에만 하위 문자열을 찾습니다.

def find_substring(string, start, end):
    len_until_end_of_first_match = string.find(start) + len(start)
    after_start = string[len_until_end_of_first_match:]
    return string[string.find(start) + len(start):len_until_end_of_first_match + after_start.find(end)]

0

그것을하는 또 다른 방법은 목록을 사용하는 것입니다 (찾고있는 하위 문자열을 바꾸는 것은 숫자로만 이루어집니다).

string = 'gfgfdAAA1234ZZZuijjk'
numbersList = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
output = []

for char in string:
    if char in numbersList: output.append(char)

print(f"output: {''.join(output)}")
### output: 1234

-1

일치하지 않는 경우 다른 문자열을 반환하는 하나의 라이너. 편집 : 개선 된 버전은 next기능을 사용 "not-found"하고 필요한 경우 다른 것으로 바꿉니다.

import re
res = next( (m.group(1) for m in [re.search("AAA(.*?)ZZZ", "gfgfdAAA1234ZZZuijjk" ),] if m), "not-found" )

덜 최적화 된이 방법을 사용하는 다른 방법은 정규식 2 시간을 사용하지만 여전히 더 짧은 방법을 찾지 못했습니다.

import re
res = ( ( re.search("AAA(.*?)ZZZ", "gfgfdAAA1234ZZZuijjk") or re.search("()","") ).group(1) )
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.