2017-04-12 158 views
1

我試圖重建一個句子:的Python如何通過一個對一個單詞列表裏的詞匹配的句子中某些符號標記的字符串來跳過部分

text='acatisananimal' 
words=['cat','is','an','a','animal'] 

for i in words: 
    if i in text: 
     final=text.replace(i,' '+i) 
     text=final 
print(final) 

的?預計產量會像:

a cat is an animal 

如果我跑我的代碼中,「一」和「一個」在「動物」將不可避免地分開了。 所以我想根據長度對單詞列表進行排序,並首先搜索長單詞。

words.sort(key=len) 
words=words[::-1] 

然後我想用特殊符號標記長單詞,並期望程序可以跳過我標記的部分。例如:

acatisan%animal& 

最後我會擦除符號。但我卡在這裏。我不知道該怎麼做才能讓程序跳過'%'和'&'之間的某些部分。誰能幫我??或者有更好的方法來解決間距問題嗎?非常感謝!

**對於另一種情況,如果文本包括不包括在單詞列表中的單詞?我怎麼會處理此事?

text=‘wowwwwacatisananimal’ 
+0

你現在的輸出是什麼? –

+0

@ t.m.adam嗯,我知道。但是,當我在評論的上下文中使用定義時,我問的是「最終」初始化_任何地方_。但是,是的,你完全正確。 –

+0

[我的解決方案](http://stackoverflow.com/a/43366440/5811078)也適用於這種情況。 – zipa

回答

2

也許你可以用食指替換詞,所以在final字符串應該是這樣的3 0 1 2 4,然後將其轉換回一句:

text='acatisananimal' 
words=['cat','is','an','a','animal'] 


for i in sorted(words,key=len,reverse=True): 
    if i in text: 
     final=text.replace(i,' %s'%words.index(i)) 
     text=final 
print(" ".join(words[int(i)] for i in final.split())) 

輸出:

a cat is an animal 
+0

某種程度上,我認爲這種方式不是很好,也許會帶來意想不到的結果,我會繼續尋找更好的解決方案。 – McGrady

+0

當大寫字母出現時會報告錯誤,我可以創建另一個大寫字母的列表。這非常有效。謝謝 – toyhtoza

1

你需要一個小的修改在你的代碼,更新代碼行

final=text.replace(i,' '+i) 

to 

final=text.replace(i,' '+i, 1)。這將只取代第一次出現。

所以更新的代碼將

text='acatisananimal' 
words=['cat','is','an','a','animal'] 
for i in words: 
if i in text: 
    final=text.replace(i,' '+i, 1) 
    text=final 
print(final) 

輸出是:

a cat is an animal 
0

如果您在僅去除符號的一部分得到......那麼正則表達式是你的,你在找什麼for..import一個名爲re的模塊並執行此操作。

import re 
code here 
print re.sub(r'\W+', ' ', final) 
3

一個更廣義的辦法是找一開始所有有效的話,分裂他們的時間,探索信件的其餘部分,例如:

def compose(letters, words): 
    q = [(letters, [])] 
    while q: 
     letters, result = q.pop() 
     if not letters: 
      return ' '.join(result) 
     for word in words: 
      if letters.startswith(word): 
       q.append((letters[len(word):], result+[word])) 

>>> words=['cat','is','an','a','animal'] 
>>> compose('acatisananimal', words) 
'a cat is an animal' 

如果有潛在的多個可能的話將它變成微不足道的組合來將其變成發生器並用yield代替return以產生所有匹配的句子組成。

人爲的例子(只是returnyield替換):

>>> words=['adult', 'sex', 'adults', 'exchange', 'change'] 
>>> list(compose('adultsexchange', words)) 
['adults exchange', 'adult sex change'] 
+0

對不起,我是Python的初學者,我正在使用python3。這個程序打印出來有些麻煩。它打印了許多包含許多括號和引號的列表。你能幫我打印一個漂亮的結果嗎?謝謝! – toyhtoza

+0

它似乎是印刷每一步。我試圖將打印參數放在循環的外面,但它給出了陌生人輸出 – toyhtoza

+0

您應該需要打印該功能的結果,例如, 'print(compose('...',words))' – AChampion

1

我不會建議使用您匹配的單詞不同的定界符兩邊

它更容易(%並在你的例子&。)在標記的單詞的任一側使用相同的分隔符並使用Python的列表分片。

以下解決方案使用[::n]語法獲取列表中的每個n個元素。

a[::2]得到偶數編號的元素,a[1::2]得到奇數。

>>> fox = "the|quick|brown|fox|jumpsoverthelazydog" 

因爲他們兩邊|字符,'quick''fox'是奇數的元素,當你劈在|字符串:

>>> splitfox = fox.split('|') 
>>> splitfox 
['the', 'quick', 'brown', 'fox', 'jumpsoverthelazydog'] 
>>> splitfox[1::2] 
['quick', 'fox'] 

,其餘均爲偶數:

>>> splitfox[::2] 
['the', 'brown', 'jumpsoverthelazydog'] 

因此,通過將|字符中的已知單詞括起來,分割並掃描even-nu複雜的元素,您只能搜索那些尚未匹配的文本部分。這意味着你在已經匹配的單詞中不匹配。

from itertools import chain 


def flatten(list_of_lists): 
    return chain.from_iterable(list_of_lists) 


def parse(source_text, words): 
    words.sort(key=len, reverse=True) 
    texts = [source_text, ''] # even number of elements helps zip function 
    for word in words: 
     new_matches_and_text = [] 
     for text in texts[::2]: 
      new_matches_and_text.append(text.replace(word, f"|{word}|")) 
     previously_matched = texts[1::2] 
     # merge new matches back in 
     merged = '|'.join(flatten(zip(new_matches_and_text, previously_matched))) 
     texts = merged.split('|') 
    # remove blank words (matches at start or end of a string) 
    texts = [text for text in texts if text] 
    return ' '.join(texts) 

>>> parse('acatisananimal', ['cat', 'is', 'a', 'an', 'animal']) 
'a cat is an animal' 
>>> parse('atigerisanenormousscaryandbeautifulanimal', ['tiger', 'is', 'an', 'and', 'animal']) 
'a tiger is an enormousscary and beautiful animal' 

merge代碼使用zipflatten功能拼接的新比賽和老一起匹配。它基本上是通過將列表中的偶數和奇數元素進行配對來實現的,然後將結果「拼合」成一個長列表,爲下一個單詞做好準備。

該方法在文本中留下無法識別的單詞。

'beautiful''a'處理得好,因爲他們對自己的(即靠近識別的單詞。)

'enormous''scary'不是已知的,因爲他們是彼此相鄰,他們離開粘在一起。

下面是如何列出未知的話:

>>> known_words = ['cat', 'is', 'an', 'animal'] 
>>> sentence = parse('anayeayeisananimal', known_words) 
>>> [word for word in sentence.split(' ') if word not in known_words] 
['ayeaye'] 

我很好奇:這是一個生物信息學項目?

+0

非常感謝!這很有幫助。這只是一個單詞重建任務。我發現像我這樣的初學者真的很難找出它:( – toyhtoza

+0

嗨@toyhtoza,好吧然後我的方法確實是矯枉過正了!但我想知道,爲什麼你會打擾重構句子,失去了單詞之間的空格呢?這看起來不像現實世界的問題 – Nick

+0

這不是初學者的代碼:這就是爲什麼我要做一些解釋,理解需要一些努力,注意你不需要理解'flatten',這只是一個有用的我從https://docs.python.org/2/library/itertools.html獲得的實用程序。我認爲,如果逐行逐行查看中間結果,則可以瞭解其餘代碼。 – Nick

0

列表和字典的理解是另一種方式來做到這一點:

result = ' '.join([word for word, _ in sorted([(k, v) for k, v in zip(words, [text.find(word) for word in words])], key=lambda x: x[1])]) 

所以,我用zip單詞及其在文本位置,sorted的話通過他們的位置在原始文本結合,最後加入結果與' '

+0

'Simple is (來自https://www.python.org/dev/peps/pep-0020/) – boardrider

+0

@boardrider理解是一種解決循環的非常快速和pythonic的方式。你有建議讓它更好? – zipa

+0

雖然確實,列表理解速度很快,性能在這裏似乎不是一個問題,@ zipa - 正如我在Python的_Zen引用中指出的那樣,_優選(和Pythonic)使用*簡單理解*語法,而不是你提出的幾乎難以理解的長期理解。 – boardrider

相關問題