Python正则表达式保留了一些令牌

时间:2015-05-22 10:14:23

标签: python regex

我在Python中使用以下正则表达式来保留不包含非字母字符的单词:

(?<!\S)[A-Za-z]+(?!\S)|(?<!\S)[A-Za-z]+(?=:(?!\S))

问题是这个正则表达式没有保留我想保留的单词,如下所示:

Company,
months.
third-party

换句话说,我想保留一个逗号,一个点或两个单词之间的短语。

关于如何实现这一点的任何想法?

我尝试为点添加类似|(?<!\S)[A-Za-z]+(?=\.(?!\S))的内容,但似乎没有效果。

谢谢!

编辑:

应该匹配这些:

On-line
.   These
maintenance,
other.
.  Our
Google

不应该匹配这些:

MFgwCgYEVQgBAQICAf8DSgAwRwJAW2sNKK9AVtBzYZmr6aGjlWyK3XmZv3dTINen
NY7xtb92dCTfvEjdmkDrUw==
$As_Of_12_31_20104206http://www.sec.gov/CIK0001393311instant2010-12-31T00:00:000001-01-01T00:00:00falsefalseArlington/S.Cooper
-Publisher
gaap_RealEstateAndAccumulatedDepreciationCostsCapitalizedSubsequentToAcquisitionCarryingCostsus

目前我正在使用以下python代码逐行读取文本文件:

find_words = re.compile(r'(?<!\S)[A-Za-z]+(?!\S)|(?<!\S)[A-Za-z]+(?=:(?!\S))').findall 

然后我打开文本文件

contents = open("test.txt","r") 

我在内容中逐行搜索单词:

if find_words(line.lower()) != []: lineWords=find_words(line.lower()) 
print "The words in this line are: ", lineWords 

以下列方式使用一些单词列表:

wanted1 = set(find_words(open('word_list_1.csv').read().lower()))
wanted2 = set(find_words(open('word_list_2.csv').read().lower()))
negators = set(find_words(open('word_list_3.csv').read().lower()))

我首先要从.txt文件中获取有效单词,然后检查这些单词是否属于单词列表。这两个步骤是独立的。

3 个答案:

答案 0 :(得分:1)

这不是正则表达式任务,因为你无法用regext检测单词。你必须有一本字典来检查你的单词。

所以我建议使用正则表达式将字符串拆分为非字母字符,并检查字典中是否存在所有项目。例如:

import re

words=re.split(r'\S+',my_string)
print all(i in my_dict for i in words if i)

作为替代原生,您可以使用nltk.corups as your dictionary

from nltk.corpus import wordnet
words=re.split(r'\S+',my_string)
if all(wordnet.synsets(word) for i in words if i):
       #do stuff

但是如果您想使用自己的单词列表,则需要更改正则表达式,因为它不正确而是使用前面的re.split

all_words = wanted1|wanted2|negators

with open("test.txt","r") as f :
  for line in f :
     for word in line.split():
        words=re.split(r'\S+',word)
        if all(i in all_words for i in words if i):
            print word

答案 1 :(得分:1)

您可以使用\b来检测单词的边界,而不是使用各种复杂的环视。这样,您可以使用例如\b[a-zA-Z]+(?:-[a-zA-Z]+)*\b

示例:

>>> p = r"\b[a-zA-Z]+(?:-[a-zA-Z]+)*\b"
>>> text = "This is some example text, with some multi-hyphen-words and invalid42 words in it."
>>> re.findall(p, text)
['This', 'is', 'some', 'example', 'text', 'with', 'some', 'multi-hyphen-words', 'and', 'words', 'in', 'it']

更新:似乎这样做效果不好,因为它还会检测来自网址的片段,例如:来自www的{​​{1}},secgov

相反,您可以尝试使用这种变体,使用环绕声明确说明“法律”和“法律”。字符:

http://www.sec.gov

这似乎是pass all your test-cases

让我们剖析这个正则表达式:

  • r"""(?<![^\s("])[a-zA-Z]+(?:[-'][a-zA-Z]+)*(?=[\s.,:;!?")])""" - 后面断言该单词前面有空格,引号或parens,但是例如不是一个数字(使用双重否定而不是正面的后视,所以第一个单词也匹配)
  • (?<![^\s("]) -
  • 一词的第一部分
  • [a-zA-Z]+ - 在(?:[-'][a-zA-Z]+)*'
  • 之后可选择更多字段
  • - - 前瞻断言该单词后跟空格,标点符号,引号或parens

答案 2 :(得分:1)

我提出这个正则表达式:

find_words = re.compile(r'(?:(?<=[^\w./-])|(?<=^))[A-Za-z]+(?:-[A-Za-z]+)*(?=\W|$)').findall

我最初的正则表达式中有3个部分我改变了:

中间部分:

[A-Za-z]+(?:-[A-Za-z]+)*

这允许带连字符的单词。

最后一部分:

(?=\W|$)

这有点类似于(?!\S),除了它允许字符不是像标点符号那样的空格。所以会发生这种情况,如果在匹配的单词之后,该行结束,或者存在非单词字符,那么这将允许匹配,换句话说,没有字母或数字或下划线(如果你不是这样的话)希望word_word匹配,然后您必须将\W更改为[a-zA-Z0-9])。

第一部分(可能是最复杂的):

(?:(?<=[^\w./-])|(?<=^))

它由两部分组成,它们匹配(?<=[^\w./-])(?<=^)。如果该行在要匹配的单词之前开始,则第二个允许匹配。我们不能使用(?<=[^\w./-]|^),因为来自re的python的lookbehind不能具有可变宽度([^\w./-]的长度为1且^的长度为0)。

如果在单词之前没有单词字符,句点,正斜杠或连字符,则

(?<=[^\w./-])允许匹配。

如果细分,我认为小部件相当简单,但如果您想要更详细的内容,我可以提供更多细节。