2017-11-06 4 views
1

문자 기반 n 그램을 검색하고 표시하려고합니다. 더 위의 열을 인용 없다 그러나, 경우에만 - 문자열파이썬 : 목록에서 일치하는 문자열 바꾸기

txt = "how does this work" 

목록

ngrams = ["ow ", "his", "s w"] 

에서 N-그램과 일치하고 <>로 표시하는 것입니다. 이 문자열을 찾고있는 출력은 h<ow >does t<his w>ork입니다 (2 인용 -nd 부분에 이중 일치가 있지만 예상 인용 부호는 한 쌍 이내입니다). 내가하지만, 전혀 원하는 출력을 생성하지 않습니다이 재판을 한 루프

은 :

switch = False 

for i in txt: 
    if i in "".join(ngrams) and switch == False: 
     txt = txt.replace(i, "<" + i) 
     switch = True 
    if i not in "".join(ngrams) and switch == True: 
     txt = txt.replace(i, ">" + i) 
     switch = False 

print(txt) 

어떤 도움을 크게 감상 할 수있다.

+0

대신 무엇이 생성됩니까? –

+0

'ngrams = [ 'his', 's wo', 'wor']'가 있으면 어떻게 될 것인가. ' k는 어떻게 되는가? '를 기대하십니까? –

+0

여러 경기를 처리하는 방법은 무엇입니까? 예 : 'ngrams = [ 'ab']','txt = 'abominable abs''. ' ominable abs', ' ominable s' 또는'abominable s'을 기대합니까? –

답변

2

이 솔루션은 txt 문자열 내에서 N- 그램의 모든 사본을 찾기 위해 str.find 방법을 사용하기 때문에 우리가 쉽게 경기를 중복 처리 할 수있는 설정 indices 각 사본의 인덱스를 저장 .

그런 다음 txt char 문자를 result 목록에 복사하고 필요한 경우 꺾쇠 괄호를 삽입하십시오. 이 전략은 각 .replace 호출이 전체 문자열을 다시 작성해야하기 때문에 복수 .replace 호출을 사용하여 꺾쇠 괄호를 삽입하는 것보다 효율적입니다.

내 코드가 ngram의 여러 복사본을 처리한다는 것을 보여주기 위해 데이터를 약간 확장했습니다.

how does this work now chisolm 
['ow ', 'his', 's w'] 
ow 1 
ow 20 
his 10 
his 24 
s w 12 
{1, 2, 10, 11, 12, 13, 20, 21, 24, 25} 
h<ow >does t<his w>ork n<ow >c<his>olm 

당신이 인접 그룹을 병합하려면

txt = "how does this work now chisolm" 
ngrams = ["ow ", "his", "s w"] 
print(txt) 
print(ngrams) 

# Search for all copies of each ngram in txt 
# saving the indices where the ngrams occur 
indices = set() 
for s in ngrams: 
    slen = len(s) 
    lo = 0 
    while True: 
     i = txt.find(s, lo) 
     if i == -1: 
      break 
     lo = i + slen 
     print(s, i) 
     indices.update(range(i, lo-1)) 

print(indices) 

# Copy the txt to result, inserting angle brackets 
# to show matches 
switch = True 
result = [] 
for i, u in enumerate(txt): 
    if switch: 
     if i in indices: 
      result.append('<') 
      switch = False 
     result.append(u) 
    else: 
     result.append(u) 
     if i not in indices: 
      result.append('>') 
      switch = True 

print(''.join(result)) 

출력, 우리는 쉽게 str.replace 방법을 사용하여 그렇게 할 수 있습니다. 그러나이 작업을 제대로 수행하려면 원본 데이터를 사전 처리해야하며 모든 공백을 단일 공백으로 변환해야합니다. 이를 수행하는 간단한 방법은 데이터를 분할하고 다시 참여시키는 것입니다.

txt = "how does this\nwork now chisolm hisow" 
ngrams = ["ow", "his", "work"] 

#Convert all whitespace to single spaces 
txt = ' '.join(txt.split()) 

print(txt) 
print(ngrams) 

# Search for all copies of each ngram in txt 
# saving the indices where the ngrams occur 
indices = set() 
for s in ngrams: 
    slen = len(s) 
    lo = 0 
    while True: 
     i = txt.find(s, lo) 
     if i == -1: 
      break 
     lo = i + slen 
     print(s, i) 
     indices.update(range(i, lo-1)) 

print(indices) 

# Copy the txt to result, inserting angle brackets 
# to show matches 
switch = True 
result = [] 
for i, u in enumerate(txt): 
    if switch: 
     if i in indices: 
      result.append('<') 
      switch = False 
     result.append(u) 
    else: 
     result.append(u) 
     if i not in indices: 
      result.append('>') 
      switch = True 

# Convert the list to a single string 
output = ''.join(result) 

# Merge adjacent groups 
output = output.replace('> <', ' ').replace('><', '') 
print(output) 

출력

how does this work now chisolm hisow 
['ow', 'his', 'work'] 
ow 1 
ow 20 
ow 34 
his 10 
his 24 
his 31 
work 14 
{32, 1, 34, 10, 11, 14, 15, 16, 20, 24, 25, 31} 
h<ow> does t<his work> n<ow> c<his>olm <hisow> 
+0

이 솔루션을 이용해 주셔서 감사합니다. 'ngrams'에 공백이 없으면, 예를 들어'ngrams = [ "ow", "his", "work"]'와 같이'h 을 생성하면 t n c olm'을 생성합니다. 'h n c olm'과 같이 공백을 무시하고 공백 (또는 줄 바꿈)으로 구분되는 경우 공백을 무시하고 공백을 결합하도록 수정할 수 있습니까? –

+1

@ Россарх 확실하게, 제발 내 대답을 업데이 트하십시오. –

+0

탁월한이 사후 처리 방식이 효과적입니다. 고맙습니다! –

2

이 작동합니다 :

txt = "how does this work" 
ngrams = ["ow ", "his", "s w"] 

# first find where letters match ngrams 
L = len(txt) 
match = [False]*L 
for ng in ngrams: 
    l = len(ng) 
    for i in range(L-l): 
     if txt[i:i+l] == ng: 
      for j in range(l): 
       match[i+j] = True 

# then sandwich matches with quotes 
out = [] 
switch = False 
for i in range(L): 
    if not switch and match[i]: 
     out.append('<') 
     switch = True 
    if switch and not match[i]: 
     out.append('>') 
     switch = False 
    out.append(txt[i]) 
print "".join(out) 
+1

출력은'h oes t rk'이고 OP는 'h 을 원합니다. ork' –

+0

@SandeepLade ok fixed – Julien

+1

@Julein : 이제 괜찮습니다. 내 표를 바 꾸었습니다 –

1

여기서 루프 하나만 갖는 방법이다. 나는 시간을 잰 것이고이 질문에 대한 다른 대답만큼 빠르다. 나는 그것이 썼기 때문에 그것이일지도 모르다, 나는 조금 더 명확하다고 생각한다.

n-gram에서 첫 번째 문자의 인덱스를 반복하고, 일치하는 경우 if-else 절을 ​​사용하여이 상황에서 < 또는 >을 추가해야하는지 확인합니다. 원래 txt에서 문자열 output의 끝에 추가하므로 실제로 문자열의 중간에 삽입하지는 않습니다.

txt = "how does this work" 
ngrams = set(["ow ", "his", "s w"]) 
n = 3 
prev = -n 
output = '' 
shift = 0 
open = False 
for i in xrange(len(txt) - n + 1): 
    ngram = txt[i:i + n] 
    if ngram in ngrams: 
     if i - prev > n: 
      if open: 
       output += txt[prev:prev + n] + '>' + txt[prev + n:i] + '<' 
      elif not open: 
       if prev > 0: 
        output += txt[prev + n:i] + '<' 
       else: 
        output += txt[:i] + '<' 
       open = True 
     else: 
      output += txt[prev:i] 
     prev = i 
if open: 
    output += txt[prev:prev + n] + '>' + txt[prev + n:] 
print output