代码之家  ›  专栏  ›  技术社区  ›  ooboo

使用多个单词边界分隔符将字符串拆分为单词

  •  827
  • ooboo  · 技术社区  · 17 年前

    "Hey, you - what are you doing here!?"
    

    ['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
    

    str.split() 只适用于一个参数,所以我用空格分隔后,所有单词都有标点符号。有什么想法吗?

    31 回复  |  直到 7 年前
        1
  •  644
  •   Community Mohan Dere    6 年前

    re.split()

    按模式出现的次数拆分字符串。如果在模式中使用捕获括号,则模式中所有组的文本也将作为结果列表的一部分返回。如果maxsplit为非零,则最多发生maxsplit拆分,字符串的其余部分作为列表的最后一个元素返回。(不兼容说明:在最初的Python 1.5版本中,maxsplit被忽略了。这在以后的版本中得到了修复。)

    >>> re.split('\W+', 'Words, words, words.')
    ['Words', 'words', 'words', '']
    >>> re.split('(\W+)', 'Words, words, words.')
    ['Words', ', ', 'words', ', ', 'words', '.', '']
    >>> re.split('\W+', 'Words, words, words.', 1)
    ['Words', 'words, words.']
    
        2
  •  523
  •   BartoszKP    9 年前

    正则表达式有理的情况:

    import re
    DATA = "Hey, you - what are you doing here!?"
    print re.findall(r"[\w']+", DATA)
    # Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
    
        3
  •  436
  •   Louis LC    14 年前

    另一种不使用正则表达式的快速方法是首先替换字符,如下所示:

    >>> 'a;bcd,ef g'.replace(';',' ').replace(',',' ').split()
    ['a', 'bcd', 'ef', 'g']
    
        4
  •  356
  •   Eric O. Lebigot    5 年前

    在字面上要求的问题中(拆分为多个可能的分隔符,相反,许多答案拆分为任何不是单词的东西,这是不同的)。因此,这是标题中问题的答案,它依赖于Python的标准和高效 re 模块:

    >>> import re  # Will be splitting on: , <space> - ! ? :
    >>> filter(None, re.split("[, \-!?:]+", "Hey, you - what are you doing here!?"))
    ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
    

    哪里:

    • […] 火柴 在内部列出的分离器中,
    • \- - 作为字符范围指示器(如 A-Z
    • + 或更多 filter() ,但这将不必要地在匹配的单个字符分隔符之间产生空字符串),以及
    • filter(None, …) 删除可能由前导和尾随分隔符创建的空字符串(因为空字符串具有错误的布尔值)。

    re.split()

    此外,此解决方案不受其他一些解决方案中单词中非ASCII字符问题的影响(请参阅 ghostdog74's answer ).

    模块比“手工”进行Python循环和测试更高效(在速度和简洁性方面)!

        5
  •  58
  •   TerryA    13 年前

    import string
    punc = string.punctuation
    thestring = "Hey, you - what are you doing here!?"
    s = list(thestring)
    ''.join([o for o in s if not o in punc]).split()
    
        6
  •  41
  •   Evgeni Sergeev    10 年前

    专业提示:使用 string.translate Python最快的字符串操作。

    一些证据。..

    >>> import timeit
    >>> S = 'Hey, you - what are you doing here!?'
    >>> def my_split(s, seps):
    ...     res = [s]
    ...     for sep in seps:
    ...         s, res = res, []
    ...         for seq in s:
    ...             res += seq.split(sep)
    ...     return res
    ... 
    >>> timeit.Timer('my_split(S, punctuation)', 'from __main__ import S,my_split; from string import punctuation').timeit()
    54.65477919578552
    

    re.findall() (如建议的答案所示)。更快:

    >>> timeit.Timer('findall(r"\w+", S)', 'from __main__ import S; from re import findall').timeit()
    4.194725036621094
    

    最后,我们使用 translate

    >>> from string import translate,maketrans,punctuation 
    >>> T = maketrans(punctuation, ' '*len(punctuation))
    >>> timeit.Timer('translate(S, T).split()', 'from __main__ import S,T,translate').timeit()
    1.2835021018981934
    

    用C实现,与Python中的许多字符串操作函数不同,

    maketrans() !

    split() . split() 默认情况下,将对所有空白字符进行操作,将它们分组在一起进行拆分。结果将是你想要的单词列表。这种方法比传统方法快4倍 !

        7
  •  29
  •   Georgy rassa45    7 年前

    我也有类似的困境,不想使用“re”模块。

    def my_split(s, seps):
        res = [s]
        for sep in seps:
            s, res = res, []
            for seq in s:
                res += seq.split(sep)
        return res
    
    print my_split('1111  2222 3333;4444,5555;6666', [' ', ';', ','])
    ['1111', '', '2222', '3333', '4444', '5555', '6666']
    
        8
  •  13
  •   Taylor D. Edmiston    8 年前

    str.translate(...)

    string.punctuation

    选项1-re.sub

    我惊讶地发现,到目前为止还没有答案 re.sub(...)

    import re
    
    my_str = "Hey, you - what are you doing here!?"
    
    words = re.split(r'\s+', re.sub(r'[,\-!?]', ' ', my_str).strip())
    

    re.sub(...) 内部 re.split(...)

    这还有几行,但它的优点是可以扩展,而不必检查是否需要转义正则表达式中的某个字符。

    my_str = "Hey, you - what are you doing here!?"
    
    replacements = (',', '-', '!', '?')
    for r in replacements:
        my_str = my_str.replace(r, ' ')
    
    words = my_str.split()
    

    如果能够将str.replace映射到字符串,那就太好了,但我认为这不能用不可变的字符串来实现,虽然映射到字符列表是可行的,但对每个字符进行每次替换听起来都太过分了。(编辑:功能示例见下一个选项。)

    (在Python 2中, reduce 在全局命名空间中可用,无需从functools导入。)

    import functools
    
    my_str = "Hey, you - what are you doing here!?"
    
    replacements = (',', '-', '!', '?')
    my_str = functools.reduce(lambda s, sep: s.replace(sep, ' '), replacements, my_str)
    words = my_str.split()
    
        9
  •  10
  •   ninjagecko    13 年前
    join = lambda x: sum(x,[])  # a.k.a. flatten1([[1],[2,3],[4]]) -> [1,2,3,4]
    # ...alternatively...
    join = lambda lists: [x for l in lists for x in l]
    

    然后,这变成了一个三行:

    fragments = [text]
    for token in tokens:
        fragments = join(f.split(token) for f in fragments)
    

    解释

    这就是Haskell中所谓的List monad。单子背后的想法是,一旦“在单子里”,你就“留在单子里”直到有什么东西把你带走。例如,在Haskell中,假设你映射python range(n) -> [1,2,...,n] 在列表上运行。如果结果是一个列表,它将被附加到列表中,所以你会得到这样的结果 map(range, [3,4,1]) -> [0,1,2,0,1,2,3,0]

    你可以把它抽象成一个函数 tokens=string.punctuation

    这种方法的优点:

    • 这种方法(与基于朴素正则表达式的方法不同)可以使用任意长度的令牌(正则表达式也可以使用更高级的语法)。
    • 你不仅限于代币;您可以用任意逻辑来代替每个标记,例如,其中一个“标记”可能是一个根据嵌套括号的方式进行拆分的函数。
        10
  •  7
  •   monitorius    12 年前

    我喜欢

    from itertools import groupby
    sep = ' ,-!?'
    s = "Hey, you - what are you doing here!?"
    print [''.join(g) for k, g in groupby(s, sep.__contains__) if not k]
    

    sep.__包含__

    lambda ch: ch in sep
    

    分组依据 获取我们的字符串和函数。它使用该函数将字符串分组:每当函数的值发生变化时,都会生成一个新的组。所以, sep.__包含__ 这正是我们所需要的。

    分组依据 “如果不是k” 我们用分隔符过滤掉组(因为 sep.__包含__ 加入 将其转换为字符串)。

    加入 表达式将变为惰性,因为每个组都是一个迭代器)

        11
  •  6
  •   Thomas Wouters    14 年前

    a = '11223FROM33344INTO33222FROM3344'
    a.replace('FROM', ',,,').replace('INTO', ',,,').split(',,,')
    

    ['11223', '33344', '33222', '3344']
    
        12
  •  5
  •   Corey Goldberg    17 年前

    试试这个:

    import re
    
    phrase = "Hey, you - what are you doing here!?"
    matches = re.findall('\w+', phrase)
    print matches
    

    这将打印 ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

        13
  •  4
  •   Jeremy Anifacc    8 年前

    在Python 3中,您可以使用以下方法 PY4E - Python for Everybody .

    我们可以通过使用字符串方法来解决这两个问题 lower , punctuation translate The 翻译 是最微妙的方法。以下是相关文档 翻译

    your_string.translate(your_string.maketrans(fromstr, tostr, deletestr))

    替换中的字符 fromstr tostr deletestr The from str 托斯特 可以是空字符串

    你可以看到“标点符号”:

    In [10]: import string
    
    In [11]: string.punctuation
    Out[11]: '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'  
    

    In [12]: your_str = "Hey, you - what are you doing here!?"
    
    In [13]: line = your_str.translate(your_str.maketrans('', '', string.punctuation))
    
    In [14]: line = line.lower()
    
    In [15]: words = line.split()
    
    In [16]: print(words)
    ['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
    

    有关更多信息,请参阅:

        14
  •  4
  •   Tarun Kumar Yellapu    7 年前

    使用pandas的series.str.split方法可以获得相同的结果,而不是使用re模块函数re.split。

    首先,使用上述字符串创建一个系列,然后将该方法应用于该系列。

    thestring = pd.Series("Hey, you - what are you doing here!?") thestring.str.split(pat = ',|-')

    参数 输出如下:

    [Hey, you , what are you doing here!?]

        15
  •  3
  •   antyrat Andy    14 年前

    tokens = [x.strip() for x in data.split(',')]
    
        16
  •  3
  •   Ritesh Sinha    8 年前

    import string
    specials = ',.!?:;"()<>[]#$=-/'
    trans = string.maketrans(specials, ' '*len(specials))
    body = body.translate(trans)
    words = body.strip().split()
    
        17
  •  2
  •   cosmicFluke    11 年前

    首先,我不认为你的意图是在分割函数中实际使用标点符号作为分隔符。你的描述表明,你只是想消除结果字符串中的标点符号。

    我经常遇到这种情况,我通常的解决方案不需要重新考虑。

    一个带列表理解的线性lambda函数:

    import string ):

    split_without_punc = lambda text : [word.strip(string.punctuation) for word in 
        text.split() if word.strip(string.punctuation) != '']
    
    # Call function
    split_without_punc("Hey, you -- what are you doing?!")
    # returns ['Hey', 'you', 'what', 'are', 'you', 'doing']
    


    作为一个传统函数,这仍然只有两行具有列表理解(除了 ):

    def split_without_punctuation2(text):
    
        # Split by whitespace
        words = text.split()
    
        # Strip punctuation from each word
        return [word.strip(ignore) for word in words if word.strip(ignore) != '']
    
    split_without_punctuation2("Hey, you -- what are you doing?!")
    # returns ['Hey', 'you', 'what', 'are', 'you', 'doing']
    

    它也会自然地保留缩写和连字符单词的完整性。您始终可以使用 text.replace("-", " ")

    不带Lambda或列表理解的通用函数

    def split_without(text: str, ignore: str) -> list:
    
        # Split by whitespace
        split_string = text.split()
    
        # Strip any characters in the ignore string, and ignore empty strings
        words = []
        for word in split_string:
            word = word.strip(ignore)
            if word != '':
                words.append(word)
    
        return words
    
    # Situation-specific call to general function
    import string
    final_text = split_without("Hey, you - what are you doing?!", string.punctuation)
    # returns ['Hey', 'you', 'what', 'are', 'you', 'doing']
    

    当然,您也可以将lambda函数推广到任何指定的字符串。

        18
  •  2
  •   Wood    7 年前

    >>> import re
    >>> def split_words(text):
    ...     rgx = re.compile(r"((?:(?<!'|\w)(?:\w-?'?)+(?<!-))|(?:(?<='|\w)(?:\w-?'?)+(?=')))")
    ...     return rgx.findall(text)
    

    它似乎工作得很好,至少对于下面的例子来说是这样。

    >>> split_words("The hill-tops gleam in morning's spring.")
    ['The', 'hill-tops', 'gleam', 'in', "morning's", 'spring']
    >>> split_words("I'd say it's James' 'time'.")
    ["I'd", 'say', "it's", "James'", 'time']
    >>> split_words("tic-tac-toe's tic-tac-toe'll tic-tac'tic-tac we'll--if tic-tac")
    ["tic-tac-toe's", "tic-tac-toe'll", "tic-tac'tic-tac", "we'll", 'if', 'tic-tac']
    >>> split_words("google.com email@google.com split_words")
    ['google', 'com', 'email', 'google', 'com', 'split_words']
    >>> split_words("Kurt Friedrich Gödel (/ˈɡɜːrdəl/;[2] German: [ˈkʊɐ̯t ˈɡøːdl̩] (listen);")
    ['Kurt', 'Friedrich', 'Gödel', 'ˈɡɜːrdəl', '2', 'German', 'ˈkʊɐ', 't', 'ˈɡøːdl', 'listen']
    >>> split_words("April 28, 1906 – January 14, 1978) was an Austro-Hungarian-born Austrian...")
    ['April', '28', '1906', 'January', '14', '1978', 'was', 'an', 'Austro-Hungarian-born', 'Austrian']
    
        19
  •  1
  •   badas    15 年前

    nltk ).

    import nltk
    data= "Hey, you - what are you doing here!?"
    word_tokens = nltk.tokenize.regexp_tokenize(data, r'\w+')
    print word_tokens
    

    ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

    install the nltk package .

    a lot of fun stuff 一旦您获得令牌,就可以使用nltk包的其余部分。

        20
  •  1
  •   lovasoa    10 年前

    @ghostdog74启发了我,也许有人觉得我的解决方案有用

    str1='adj:sg:nom:m1.m2.m3:pos'
    splitat=':.'
    ''.join([ s if s not in splitat else ' ' for s in str1]).split()
    

    在空格处输入内容,若不想在空格处拆分,请使用相同的字符进行拆分。

        21
  •  1
  •   Tasneem Haider    10 年前

    因此,对于您的问题,首先编译模式,然后对其执行操作。

    import re
    DATA = "Hey, you - what are you doing here!?"
    reg_tok = re.compile("[\w']+")
    print reg_tok.findall(DATA)
    
        22
  •  1
  •   fpietka AdrianBR    8 年前

    以下是答案,并附有一些解释。

    st = "Hey, you - what are you doing here!?"
    
    # replace all the non alpha-numeric with space and then join.
    new_string = ''.join([x.replace(x, ' ') if not x.isalnum() else x for x in st])
    # output of new_string
    'Hey  you  what are you doing here  '
    
    # str.split() will remove all the empty string if separator is not provided
    new_list = new_string.split()
    
    # output of new_list
    ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
    
    # we can join it to get a complete string without any non alpha-numeric character
    ' '.join(new_list)
    # output
    'Hey you what are you doing'
    

    或者在一行中,我们可以这样做:

    (''.join([x.replace(x, ' ') if not x.isalnum() else x for x in st])).split()
    
    # output
    ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
    

        23
  •  1
  •   Everett    7 年前

    创建一个函数,将两个字符串(要拆分的源字符串和分隔符的splitlist字符串)作为输入,并输出一个拆分单词列表:

    def split_string(source, splitlist):
        output = []  # output list of cleaned words
        atsplit = True
        for char in source:
            if char in splitlist:
                atsplit = True
            else:
                if atsplit:
                    output.append(char)  # append new word after split
                    atsplit = False
                else: 
                    output[-1] = output[-1] + char  # continue copying characters until next split
        return output
    
        24
  •  1
  •   Martlark    6 年前

    我喜欢pprzemek的解决方案,因为它不假设分隔符是单个字符,也不试图利用正则表达式(如果分隔符的数量太长,正则表达式将无法很好地工作)。

    为了清楚起见,这里有一个更易读的上述解决方案版本:

    def split_string_on_multiple_separators(input_string, separators):
        buffer = [input_string]
        for sep in separators:
            strings = buffer
            buffer = []  # reset the buffer
            for s in strings:
                buffer = buffer + s.split(sep)
    
        return buffer
    
        25
  •  0
  •   Martlark    14 年前

    以下是我与多名脱口者的分手经历:

    def msplit( str, delims ):
      w = ''
      for z in str:
        if z not in delims:
            w += z
        else:
            if len(w) > 0 :
                yield w
            w = ''
      if len(w) > 0 :
        yield w
    
        26
  •  0
  •   Yugal Jindle    14 年前

    \W+ 可能适合这种情况,但可能不适合其他情况。

    filter(None, re.compile('[ |,|\-|!|?]').split( "Hey, you - what are you doing here!?")
    
        27
  •  0
  •   Arindam Roychowdhury    13 年前

    def split_string(source,splitlist):
        splits = frozenset(splitlist)
        l = []
        s1 = ""
        for c in source:
            if c in splits:
                if s1:
                    l.append(s1)
                    s1 = ""
            else:
                print s1
                s1 = s1 + c
        if s1:
            l.append(s1)
        return l
    
    >>>out = split_string("First Name,Last Name,Street Address,City,State,Zip Code",",")
    >>>print out
    >>>['First Name', 'Last Name', 'Street Address', 'City', 'State', 'Zip Code']
    
        28
  •  0
  •   Stefan van den Akker Raymond Hettinger    12 年前

    replace() splitlist 拆分列表 恰好是一个空字符串。它返回一个单词列表,其中没有空字符串。

    def split_string(text, splitlist):
        for sep in splitlist:
            text = text.replace(sep, splitlist[0])
        return filter(None, text.split(splitlist[0])) if splitlist else [text]
    
        29
  •  0
  •   anon582847382    12 年前
    def get_words(s):
        l = []
        w = ''
        for c in s.lower():
            if c in '-!?,. ':
                if w != '': 
                    l.append(w)
                w = ''
            else:
                w = w + c
        if w != '': 
            l.append(w)
        return l
    

    >>> s = "Hey, you - what are you doing here!?"
    >>> print get_words(s)
    ['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
    
        30
  •  0
  •   Nathan B    8 年前

    def tokenizeSentence_Reversible(sentence):
        setOfDelimiters = ['.', ' ', ',', '*', ';', '!']
        listOfTokens = [sentence]
    
        for delimiter in setOfDelimiters:
            newListOfTokens = []
            for ind, token in enumerate(listOfTokens):
                ll = [([delimiter, w] if ind > 0 else [w]) for ind, w in enumerate(token.split(delimiter))]
                listOfTokens = [item for sublist in ll for item in sublist] # flattens.
                listOfTokens = filter(None, listOfTokens) # Removes empty tokens: ''
                newListOfTokens.extend(listOfTokens)
    
            listOfTokens = newListOfTokens
    
        return listOfTokens