I'm writing a Python function to split text into words, ignoring specified punctuation. Here is some working code. I'm not convinced that constructing strings out of lists (buf = [] in the code) is efficient though. Does anyone have a suggestion for a better way to do this?
def getwords(text, splitchars=' \t|!?.;:"'):
"""
Generator to get words in text by splitting text along specified splitchars
and stripping out the splitchars::
>>> list(getwords('this is some text.'))
['this', 'is', 'some', 'text']
>>> list(getwords('and/or'))
['and', 'or']
>>> list(getwords('one||two'))
['one', 'two']
>>> list(getwords(u'hola unicode!'))
[u'hola', u'unicode']
"""
splitchars = set(splitchars)
buf = []
for char in text:
if char not in splitchars:
buf.append(char)
else:
if buf:
yield ''.join(buf)
buf = []
# All done. Yield last word.
if buf:
yield ''.join(buf)
From stackoverflow
-
You don't want to use re.split?
import re re.split("[,; ]+", "coucou1 , coucou2;coucou3")Jace : Didn't think of that at all. Will consider it. Thanks! -
http://www.skymind.com/~ocrow/python_string/ talks about several ways of concatenating strings in Python and assesses their performance as well.
Jace : This was what I needed. Thanks. cStringIO appears the best choice for my use case.Jace : Uh oh. cStringIO can't handle unicode strings.kquinn : For what it's worth: I hacked on that testcase until it ran on my Python 2.5 install, and found Method 6 (feed ''.join a list comprehension) to be consistently fastest. 6 with generator expressions turned out *slower* but still second-fastest.kquinn : In order from fastest to slowest, the methods ended up being 6, 7, 4, 1, 5, 3, 2. (7 is 6 with the brackets dropped to make it a generator expression not list comprehension). I was unable to measure memory use. -
You can split the input using
re.split():>>> splitchars=' \t|!?.;:"' >>> re.split("[%s]" % splitchars, "one\ttwo|three?four") ['one', 'two', 'three', 'four'] >>>EDIT: If your
splitcharsmay contain special chars like]or^, you can usere.escpae()>>> re.escape(splitchars) '\\ \\\t\\|\\!\\?\\.\\;\\:\\"' >>> re.split("[%s]" % re.escape(splitchars), "one\ttwo|three?four") ['one', 'two', 'three', 'four'] >>>Jace : That one's risky. What if splitchars starts with a '^' or contains a ']'?gimel : Escape them. See edit. -
You can use re.split
re.split('[\s|!\?\.;:"]', text)However if the text is very large the resulting array may be consuming too much memory. Then you may consider re.finditer:
import re def getwords(text, splitchars=' \t|!?.;:"'): words_iter = re.finditer( "([%s]+)" % "".join([("^" + c) for c in splitchars]), text) for word in words_iter: yield word.group() # a quick test s = "a:b cc? def...a||" words = [x for x in getwords(s)] assert ["a", "b", "cc", "def", "a"] == words, words
0 comments:
Post a Comment