string空格分割 - split python空格




分割字符串與多個分隔符? (19)

我認為我想要做的是一個相當常見的任務,但我沒有在網上找到任何參考。 我有文字,標點符號,我想要單詞列表。

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

應該

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

但是,Python的str.split()只能用於一個參數...因此,在用空格分隔後,我將所有帶有標點符號的單詞都包含str.split() 。 有任何想法嗎?


re.split()

re.split(pattern,string [,maxsplit = 0])

根據模式的出現拆分字符串。 如果在模式中使用捕獲括號,則模式中所有組的文本也會作為結果列表的一部分返回。 如果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.']


使用列表解析這個東西...它似乎更容易

data= "Hey, you - what are you doing here!?"
tokens = [c for c in data if c not in (',', ' ', '-', '!', '?')]

我發現這比使用正則表達式更容易理解(read..maintain),僅僅因為我對正則表達式不太擅長......我們大多數人都是這樣:)。 同樣,如果你知道你可能使用了哪些分隔符,你可以把它們放在一個集合中。 有一個非常龐大的集合,這可能會更慢......但're'模塊也很慢。


使用替換兩次:

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

結果是:

['11223', '33344', '33222', '3344']

另一種方式,沒有正則表達式

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()

另一種方法是使用自然語言工具包( 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']

這種方法最大的缺點是你需要安裝nltk軟件包

好處是,一旦你獲得了令牌,你就可以用nltk包的其餘部分做很多有趣的事情


如果你想要一個可逆操作(保留分隔符),你可以使用這個函數:

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

如果沒有正則表達式,另一個快速的方法是首先替換字符,如下所示:

>>> 'a;bcd,ef g'.replace(';',' ').replace(',',' ').split()
['a', 'bcd', 'ef', 'g']

得到和@ooboo相同的問題,並找到這個話題@ ghostdog74啟發了我,也許有人發現我的解決方案有用

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

在空間位置輸入一些東西,如果你不想在空間處分割,則使用相同的字符進行分割。


我喜歡replace()方式最好。 以下過程將字符串splitlist定義的所有分隔符更改為splitlist中的第一個分隔符,然後拆分該分隔符上的文本。 它也說明了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]

我認為以下是滿足您的需求的最佳答案:

\W+可能適合這種情況,但可能不適用於其他情況。

filter(None, re.compile('[ |,|\-|!|?]').split( "Hey, you - what are you doing here!?")

我重新熟悉Python,需要同樣的東西。 findall解決方案可能會更好,但我想出了這個:

tokens = [x.strip() for x in data.split(',')]

正則表達式合理的情況:

import re
DATA = "Hey, you - what are you doing here!?"
print re.findall(r"[\w']+", DATA)
# Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

繼承人我的承擔....

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']

這裡有一些解釋的答案。

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']

更新的答案


這麼多的答案,但我找不到任何解決方案,有效地問題標題字面上要求(分裂與多個分隔符 - 相反,許多答案刪除任何不是一個字,這是不同的)。 所以這裡是標題中的問題的答案,它依賴於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']

哪裡:

  • \-在正則表達式中,這裡是為了防止特殊解釋-作為字符範圍指示符,
  • +跳過一個或多個分隔符,並且
  • filter(None, …)刪除可能由前導和尾隨分隔符創建的空字符串(因為空字符串具有假布爾值)。

正如問題標題中所要求的,這個re.split()正好“與多個分隔符分開”。

該解決方案也不會遇到非ASCII字符的問題(請參閱ghostdog74答案的第一條評論)。

re模塊比“循環”Python循環和測試更有效率。


首先,我不認為你的意圖是在分割函數中實際使用標點符號作為分隔符。 你的描述表明你只是想從結果字符串中消除標點符號。

我經常遇到這種情況,而我通常的解決方案並不需要重複。

單線lambda函數w / list理解:

(需要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']


功能(傳統)

作為一個傳統的函數,這仍然只有兩條帶有列表理解的行(除了import string ):

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函數概括為任何指定的字符串。


首先,我想與其他人一致認為基於正則表達式或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.split(...) re.sub(...) - 但是如果性能很關鍵,編譯外部正則表達式可能是有益的 - 對我的用例而言, t顯著,所以我更喜歡簡單性和可讀性。

選項2 - str.replace

這還有幾行,但它具有可擴展的好處,而無需檢查是否需要在正則表達式中轉義某個字符。

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映射到字符串本來是很好的,但我不認為它可以用不可變的字符串來完成,並且在映射字符列表的時候可以工作,對每個字符運行每個替換聽起來過度。 (編輯:查看下一個選項的功能示例。)

選項3 - functools.reduce

(在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()

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的原因。 monad背後的想法是,一旦“在monad中”,你“停留在monad中”,直到有某種東西把你帶出去。 例如在Haskell中,假設您將Python range(n) -> [1,2,...,n]映射到List上。 如果結果是一個List,它將被附加到列表就地,所以你會得到像map(range, [3,4,1]) -> [0,1,2,0,1,2,3,0] 。 這被稱為map-append(或mappend,或者類似的東西)。 這裡的想法是,你已經應用了這個操作(分割一個令牌),並且每當你這樣做時,你都會將結果加入到列表中。

你可以將它抽象為一個函數,並且默認情況下有tokens=string.punctuation

這種方法的優點:

  • 這種方法(不同於真正的基於正則表達式的方法)可以使用任意長度的標記(正則表達式也可以使用更高級的語法)。
  • 你不僅僅限於令牌; 你可以用任意的邏輯代替每個標記,例如其中一個“標記”可以是根據嵌套括號如何分割的函數。




split