2017-04-12 159 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

相关问题