문제

다음에 다음과 같이 가정 해 봅시다.

{{Hello | Hi | Hey} {World | Earth} | {Goodbye | farewell} {noobs | n3wbz | n00blets}}

그리고 나는 그것이 다음 중 하나로 바뀌기를 원합니다.

Hello world 
Goodbye noobs 
Hi earth
farewell n3wbz 
// etc.

"회전"구문이 중첩되는 방식에주의를 기울입니다. 그것은 우리가 아는 모든 것을 위해 10 억 레이어로 중첩 될 수 있습니다.

위의 예와 같이 중첩 된 일단 내 동정형이 엉망이되고 결과가 정확하지 않은 것을 제외하고는이 작업을 쉽게 할 수 있습니다.

누군가 .net 언어 나 파이썬으로 예를 보여줄 수 있습니까?

도움이 되었습니까?

해결책

간단한 방법 re.subn, 교체 문자열 대신 함수를 수락 할 수 있습니다.

import re
from random import randint

def select(m):
    choices = m.group(1).split('|')
    return choices[randint(0, len(choices)-1)]

def spinner(s):
    r = re.compile('{([^{}]*)}')
    while True:
        s, n = r.subn(select, s)
        if n == 0: break
    return s.strip()

그것은 단순히 만나는 가장 깊은 선택을 단순히 대체 한 다음 선택의 여지가 없을 때까지 반복합니다. subn 결과와 함께 튜플을 반환하고 몇 개의 교체품이 만들어졌으며, 이는 처리의 끝을 감지하는 데 편리합니다.

내 버전 select() 사용하는 Bobince의 것으로 대체 될 수 있습니다 random.choice() 임의의 선택기를 고수하고 싶다면 더 우아합니다. Choice 트리를 만들려면 위의 기능을 확장 할 수 있지만 현재 위치를 추적하려면 전역 변수가 필요하므로 기능을 클래스로 옮기는 것이 합리적입니다. 이것은 단지 힌트입니다. 나는 그것이 실제로 orginial 질문이 아니기 때문에 그 아이디어를 개발하지 않을 것입니다.

마지막으로 사용해야합니다 r.subn(select, s, re.U) 유니 코드 스트링이 필요한 경우 (s = u"{...}")

예시:

>>> s = "{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}"
>>> print spinner(s)
'farewell n3wbz'

편집하다: 교체 sub ~에 의해 subn 무한 루프를 피하기 위해 (Bobince 덕분에 지적해 주셔서 감사합니다) 더 효율적으로 만들고 교체 {([^{}]+)} ~에 의해 {([^{}]*)} 빈 곱슬 괄호도 추출합니다. 그것은 형식화되지 않은 패턴에 더 강력하게 만들어야합니다.

한 줄에 최대한 많이 넣고 싶어하는 사람들에게 (개인적으로 권장하지 않을 것입니다) :

def spin(s):
    while True:
        s, n = re.subn('{([^{}]*)}',
                       lambda m: random.choice(m.group(1).split("|")),
                       s)
        if n == 0: break
    return s.strip()

다른 팁

상당히 간단해야합니다. 다른 사람을 포함시키는 곳에서 버팀대를 허용하지 않은 다음 반복적으로 내부 경기에서 바깥쪽으로 교체 할 수 있습니다.

def replacebrace(match):
    return random.choice(match.group(1).split('|'))

def randomizebraces(s):
   while True:
       s1= re.sub(r'\{([^{}]*)\}', replacebrace, s)
       if s1==s:
           return s
       s= s1

>>> randomizebraces('{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}')
'Hey world'
>>> randomizebraces('{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}')
'Goodbye noobs'

이것 Regex 인버터 용도 pyparsing 일치하는 문자열을 생성하려면 (일부 제한 포함 - + 및 *와 같은 무제한 반복 기호는 허용되지 않습니다). 원래 문자열을 Regex로 만들기 위해 {} 's로 ()을 바꾸면 인버터 가이 목록을 생성합니다.

Helloworld
Helloearth
Hiworld
Hiearth
Heyworld
Heyearth
Goodbyenoobs
Goodbyen3wbz
Goodbyen00blets
farewellnoobs
farewelln3wbz
farewelln00blets

(공간이 무너 졌다는 것을 알고 있지만이 코드는이 문제를 공격하는 방법에 대한 아이디어를 줄 것입니다.)

나는 Re.Finditer를 사용하고 기본 구문 분석 트리를 만들기 위해 둥지 레벨을 결정합니다. 그렇게하려면 Regex 매치 객체의 SPAN 속성을 사용합니다.

text = '{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}'

import re
re_bracks = re.compile(r'{.+?}')

# subclass list for a basic tree datatype
class bracks(list):
    def __init__(self, m):
        self.m = m

# icky procedure to create the parse tree
# I hate these but don't know how else to do it
parse_tree = []
for m in re_bracks.finditer(text):
    if not this_element:
        # this first match
        parse_tree.extend(element(m))
    else:
        # ... and all the rest
        this_element = bracks(m)
        this_start, this_end = m.span()

        # if this match is nested in the old one ...
        if this_start < previous_start and this_end > previous_end:
            # nest it inside the previous one
            previous_element.extend(this_element) 
        else:
            # otherwise make it a child of the parse_tree
            parse_tree.extend(element(m))

        previous_element = this_element
        previous_start, previous_end = this_start, this_end

이것은 당신에게 괄호로 된 표현의 중첩 깊이를 줄 것입니다. 파이프에 대해 유사한 논리를 추가하면 문제를 해결하는 데 도움이 될 것입니다.

살펴 보는 것이 좋습니다 다다 엔진 영감을 위해.

나는 내 요구를 표현하기 위해 체계와 레버리지 체계의 AST에서 영감을 얻은 것을 구현했습니다.

구체적으로, 나는 일반적으로 구문 분석기로서 선수를 사용하려고하는 것을 강력하게 추천합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top