文字列を複数の単語境界区切り文字で単語に分割する


670

私がやりたいことはかなり一般的な仕事だと思いますが、Webでの参照は見つかりませんでした。句読点のあるテキストがあり、単語のリストが必要です。

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

する必要があります

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

しかし、Python str.split()は1つの引数でのみ機能するため、空白で分割した後、すべての単語に句読点が付きます。何か案は?



6
python str.split()も引数なしで動作します
Ivan Vinogradov

回答:


467

正規表現が正当化されるケース:

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

2
ありがとう。しかし、まだ興味があります-このモジュールで使用されているアルゴリズムを実装するにはどうすればよいですか?そして、なぜそれが文字列モジュールに表示されないのですか?
ooboo 2009年

29
正規表現は最初は気が遠くなるかもしれませんが、非常に強力です。正規表現「\ w +」は、「1回以上繰り返される単語文字(azなど)」を意味します。Python正規表現に関するHOWTOがこちらにあります:amk.ca/python/howto/regex
RichieHindle

324
これは質問に対する答えではありません。これは、この特定の状況でたまたま機能する別の質問への回答です。まるで誰かが「左折するにはどうすればよいですか」と尋ねられ、トップ投票の回答が「次の3つの右折を取る」であったかのようです。特定の交差点では機能しますが、必要な答えが得られません。皮肉なことに、答えreありfindallます。以下の答えre.split()は優れています。
ジェシーディロン2013

4
@JesseDhillon「一連の単語文字で構成されるすべての部分文字列を取得する」と「一連の非単語文字で構成されるすべての部分文字列を分割する」は、同じ操作を表現するための文字通り異なる方法です。なぜどちらの回答を上司に電話するのかわかりません。
マークアメリー2015

4
@TMWP:アポストロフィは、のような単語don'tdonand に分割されるのではなく、1つの単語として扱われることを意味しtます。
RichieHindle 2017年

574

re.split()

re.split(パターン、文字列[、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.']

13
このソリューションには、アンダースコアでの分割にも簡単に適応できるという利点があります。findallソリューションではできないことです。printre.split( "\ W + | _"、 "Testing this_thing") 'は次のようになります。 、 '
シング

63
場合にのみ、今、私は違いを覚えることができる\w\W\s、と\S。旗の大文字化はその意味を逆転させるべきだと思った人は頭を打たれる必要があります。
ArtOfWarfare 2015

1
文字列分割の一般的な使用例は、最終結果から空の文字列エントリを削除することです。この方法でそれを行うことは可能ですか?re.split( '\ W +'、 'abc')結果は[''、 'a'、 'b'、 'c'、 '']
Scott Morken

3
@ArtOfWarfare shift何かの反対をするためにキーを使用することは一般的です。ctrl+z元に戻すctrl+shift+zとやり直し。つまりshift w、またはW、は反対ですw
フランクヴェル2018

1
この回答が一番上にあるはずです。質問のタイトルに正確に回答するのはこの回答だけです。
Kranach、

380

正規表現なしでこれを行う別の簡単な方法は、以下のように、最初に文字を置き換えることです。

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

71
迅速かつ汚いが、私の場合に最適(私のセパレーターは小さな既知のセットでした)
Andy Baker

7
特定の小型マイクロコントローラーなど、REライブラリにアクセスできない場合に最適です。:-)
tu-Reinstate Monica-dor duh

11
これはREよりも明確であるため、初心者にやさしいものです。時々、すべてに対する一般的な解決策は必要ありません
アダム・ヒューズ

驚くばかり。複数の入力状況で.split()があり、ユーザーである私が入力をコンマではなくスペースで区切ったときにキャッチする必要がありました。私はあきらめてreでリキャストしようとしていましたが、あなたの.replace()ソリューションは頭の釘を打ちました。ありがとう。
JayJay123 2015

スペースで分割したくない場合や、他の文字で分割したい場合は、間違った答えになります。
Ahmed Amr 2017

307

非常に多くの回答がありますが、質問のタイトルが文字通り要求するものを効率的に実行する解決策は見つかりません(複数の可能な区切り文字で分割します。代わりに、多くの回答は、単語ではないもので分割されます。違います)。タイトルの質問に対する答えは次のとおりです。これは、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']

どこ:

  • […]試合の1内部の列挙されたセパレータの、
  • \-正規表現の中の特殊な解釈を防ぐために、ここで-のように、文字範囲インジケータ(としてA-Z)、
  • +スキップ1 以上の区切り文字は、(それはへの感謝を省略することができますfilter()が、これは不必要にマッチしたセパレータの間に空の文字列を生成する)、および
  • filter(None, …) 先頭と末尾のセパレータによって作成された可能性のある空の文字列を削除します(空の文字列には偽のブール値があるため)。

これre.split()は、質問のタイトルで要求されているとおり、正確に「複数のセパレータで分割」されます。

さらに、このソリューションは、他のいくつかのソリューションで見つかった単語の非ASCII文字の問題の影響を受けません(ghostdog74の回答の最初のコメントを参照)。

このreモジュールは、Pythonループを実行して「手動」でテストするよりも(速度と簡潔さにおいて)はるかに効率的です!


3
「質問のタイトルが文字通り要求することを効率的に行うソリューションが見つかりません」-5年前に投稿された2番目の答えはそれです:stackoverflow.com/a/1059601/2642204
BartoszKP

17
この回答は、(複数の区切り文字のセットからの)区切り文字で分割されません。代わりに、英数字以外の任意の文字で分割されます。とはいえ、元のポスターの目的は、句読点を削除するのではなく、単語だけを残すことであることに同意します。
Eric O Lebigot、2014

EOL:この答えは、複数のデリミタのセットに分かれていると思います。アンダースコアなど、指定されていない英数字以外の文字列を追加すると、期待どおりに分割されません。
GravityWell 2014

@GravityWell:よくわかりません:具体例を教えていただけますか?
Eric O Lebigot、2014

3
@EOL:「この回答は分割されません...」というコメントに混乱していることに気づきました この答え(私がコメントしている答え)が最良の答えだと思います:)
GravityWell

56

別の方法、正規表現なし

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

8
このソリューションは、実際に受け入れられているソリューションよりも優れています。ASCII文字なしで動作し"Hey, you - what are you doing here María!?"ます。承認されたソリューションは、前の例では機能しません。
クリストファーラミレス

4
ここに小さな問題があると思います...コードは句読点で区切られた文字を追加するため、それらは分割されません...私が間違っていなければ、最後の行は次のようになります:''.join([o if not o in string.punctuation else ' ' for o in s]).split()
cedbeu

正規表現ライブラリは、必要に応じて文字のUnicode規則を受け入れるように作成できます。さらに、これには、受け入れられた解決策が持っていたのと同じ問題があります。今のところ、アポストロフィで分割されています。したいかもしれませんo for o in s if (o in not string.punctuation or o == "'")が、cedbeuのパッチも追加すると、ワンライナーには複雑になります。
ダニエルH

ここには別の問題があります。@cedbeuの変更を考慮しても、文字列が次のようなもの"First Name,Last Name,Street Address,City,State,Zip Code"で、コンマでのみ分割したい場合、このコードは機能しません,。望ましい出力は次のとおり['First Name', 'Last Name', 'Street Address', 'City', 'State', 'Zip Code']です。代わりに何が得られるか:['First', 'Name', 'Last', 'Name', 'Street', 'Address', 'City', 'State', 'Zip', 'Code']
Stefan van den Akker 14

4
このソリューションはひどく非効率的です。最初にリストが個々の文字に分解され、次に句読文字のセット全体が元の文字列の単一の文字ごとに処理され、次に文字が組み立てられてから、再び分割されます。このすべての「動き」も、正規表現ベースのソリューションと比較して非常に複雑です。特定のアプリケーションで速度が問題にならない場合でも、複雑なソリューションは必要ありません。reモジュールは標準であり、読みやすさと速度の両方を提供するため、なぜそれを避けるべきかわかりません。
エリックOレビゴット2015年

39

プロのヒント:使用 string.translate Pythonが持つ最速の文字列操作にします。

いくつかの証拠...

まず、遅い方法(申し訳ありませんがpprzemek):

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

説明:

string.translateCで実装され、Pythonの多くの文字列操作関数とは異なり、新しい文字列を生成string.translate しません。そのため、文字列の置換が可能な限り高速です。

ただし、この魔法を行うには変換テーブルが必要なので、少し厄介です。maketrans()便利な機能で変換テーブルを作ることができます。ここでの目的は、すべての不要な文字をスペースに変換することです。1対1の代替。この場合も、新しいデータは生成されません。これは速いです!

次に、古き良きを使用しますsplit()split()デフォルトでは、すべての空白文字を操作して、分割のためにグループ化します。結果は、必要な単語のリストになります。そして、このアプローチはre.findall()


4
ここでテストを行いましたが、Unicodeを使用する必要がある場合patt = re.compile(ur'\w+', re.UNICODE); patt.findall(S)は、変換を適用する前に文字列をエンコードし、Unicodeに戻るには、分割後にリストの各項目をデコードする必要があるため、使用する方が変換よりも高速です。
Rafael S. Calsaverini 2013年

あなたはワンライナーの実装を翻訳し、Sはとスプリッタの中にないことを確認することができます:s.translate(''.join([(chr(i) if chr(i) not in seps else seps[0]) for i in range(256)])).split(seps[0])
コンロ

何も取られていません。リンゴとオレンジを比較しています。;)python 3での私の解決策は引き続き機能し、; Pであり、複数文字の区切り文字をサポートしています。:)新しい文字列を割り当てずに、簡単な方法でそれを試してください。:)しかし、本当では、コマンドラインパラメータの解析に限定されており、たとえば本には限定されていません。
pprzemek 2017年

あなたは「新しい文字列を生成しない」と言います、それはそれが与えられた文字列でその場で機能することを意味しますか?私はそれをpython 2.7でテストしましたが、元の文字列を変更せず、新しい文字列を返します。
Prokop Hapala

26

同様のジレンマがあり、「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']

1
私はこれが好き。ただの注意ですが、セパレータの順序は重要です。それが明らかな場合は申し訳ありません。
crizCraig 2011年

2
reどちらの方法も高速かつ明確なモジュールを使用しないのはなぜですか(正規表現は特に明確ではありませんが、非常に短く直接的なため)。
Eric O Lebigot 2014年

13

最初に、正規表現またはstr.translate(...)ベースのソリューションが最もパフォーマンスが高いことを他の人に同意したいと思います。私のユースケースでは、この関数のパフォーマンスはそれほど重要ではなかったので、その基準で検討したアイデアを追加したいと思いました。

私の主な目的は、他のいくつかの回答からのアイデアを、正規表現以外の単語を含む文字列で機能する1つのソリューションに一般化することでした(つまり、句読文字の明示的なサブセットのブラックリストと単語文字のホワイトリスト)。

どのアプローチでも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(...)—パフォーマンスが重要な場合、外部で正規表現をコンパイルすることは有益かもしれません—私の使用例では、違いは重要ではなかったので、単純さと読みやすさを優先します。

オプション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では、reducefunctoolsからインポートせずにグローバル名前空間で使用できます。)

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

うーん、もう1つの方法は使用するstr.translateことです。Unicode対応ではありませんが、他の方法よりも高速である可能性が高いため、場合によっては適切な場合もあります。replacements=',-!?'; import string; my_str = my_str.translate(string.maketrans(replacements, ' ' * len(replacements)))また、タプルやリスト。
MarSoft

@MarSoftありがとう!1つは回答の一番上にあると述べましたが、既存の回答はすでに十分に議論しているため、追加しないことにしました。
テイラーエドミストン2017

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

次に、これは3行になります。

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

説明

これはHaskellではListモナドとして知られているものです。モナドの背後にある考え方は、いったん「モナドに」入ると、何かがあなたを連れ出すまで「モナドにとどまる」というものです。たとえば、Haskellで、Python range(n) -> [1,2,...,n]関数をリストにマッピングするとします。結果がリストの場合は、その場でリストに追加されるので、のようなものが得られますmap(range, [3,4,1]) -> [0,1,2,0,1,2,3,0]。これはmap-append(またはmappend、あるいはそのようなもの)として知られています。ここでの考え方は、適用している(トークンで分割する)この操作があり、それを実行するたびに、結果をリストに結合するということです。

これを関数に抽象化してtokens=string.punctuation、デフォルトで持つことができます。

このアプローチの利点:

  • このアプローチは(単純な正規表現ベースのアプローチとは異なり)任意の長さのトークンで機能します(正規表現はより高度な構文でも実行できます)。
  • あなたは単なるトークンに制限されていません。各トークンの代わりに任意のロジックを使用できます。たとえば、「トークン」の1つは、ネストされた括弧がどのようにあるかに応じて分割する関数である可能性があります。

きちんとしたHaskellソリューションですが、IMOこれはPythonのmappendなしでより明確に記述できます。
Vlad the Impala、2011年

@Goose:重要なのは、2行関数map_then_appendを使用して問題を2 行にできること、および他の多くの問題をより簡単に記述できることです。他のほとんどのソリューションは、rePythonではない正規表現モジュールを使用します。しかし、私は自分の答えが本当に簡潔で上品で膨らんでいるように見えることに不満を感じていました...私はそれを編集します...
ninjagecko

これは書かれたままのPythonで動作するはずですか?私のfragments結果は、文字列(トークンを含む)内の文字のリストです。
リックはモニカをサポート

@RickTeachey:python2とpython3の両方で動作します。
ninjagecko

うーん。多分この例は少しあいまいです。私は答えでコードを試してみましたが、、、またはを含むさまざまな方法がfragments = ['the,string']ありfragments = 'the,string'fragments = list('the,string')どれも正しい出力を生成していません。
Rickは2017年

5

これを試して:

import re

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

これは印刷されます ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']


4

replaceを2回使用します。

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

結果は:

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

4

私はreが好きですが、ここにそれなしの私の解決策があります:

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 .__ contains__は、「in」演算子で使用されるメソッドです。基本的には同じです

lambda ch: ch in sep

ここではより便利です。

groupbyは文字列と関数を取得します。関数を使用して文字列をグループに分割します。関数の値が変更されるたびに、新しいグループが生成されます。したがって、sep .__ contains__はまさに必要なものです。

groupbyはペアのシーケンスを返します。ここで、pair [0]は関数の結果で、pair [1]はグループです。使用して、K「でない場合は、」私たちはセパレータでグループをフィルタリング(の結果ので、9月.__ contains__は、セパレータに真です)。さて、これですべてです。これで、それぞれが単語である一連のグループができました(グループは実際には反復可能であるため、結合を使用して文字列に変換します)。

関数を使用して文字列を分離するため、このソリューションは非常に一般的です(必要な任意の条件で分割できます)。また、中間の文字列やリストは作成されません(結合を削除すると、各グループがイテレータであるため、式が遅延になります)。


4

reモジュール関数re.splitを使用する代わりに、pandasのseries.str.splitメソッドを使用して同じ結果を得ることができます。

最初に、上記の文字列でシリーズを作成してから、メソッドをシリーズに適用します。

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

パラメータpatは区切り文字を受け取り、分割された文字列を配列として返します。ここでは、2つの区切り文字が|を使用して渡されます。(または演算子)。出力は次のとおりです。

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


1
これは冗長な問題ではなく、文字列をパンダシリーズに変換した後で単純なタスクを実行するために、ライブラリ全体(私が好きなのはBTW)をインポートするという事実です。「Occamフレンドリー」ではない。
zar3bski

3

私はPythonに慣れ親しんでおり、同じことを必要としていました。findallソリューションの方が良いかもしれませんが、私はこれを思いつきました:

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

賢いです。たとえば、スペースのない全角ダッシュを除いて、私が考えることができるすべての英語の文法構文(これなど)に取り組む必要があります。(回避可能。)
ninjagecko 2013年

3

maketransとtranslateを使用すると、簡単かつきちんとそれを行うことができます

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

Pythonの
revliscano

3

Python 3では、PY4E-Python for Everybodyのメソッドを使用できます。

私たちは、文字列のメソッドを使用することにより、これらの問題の両方を解決することができlowerpunctuationtranslatetranslateメソッドの中で最も微妙です。ここにドキュメントがありますtranslate

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

fromstrの文字をの同じ位置の文字に置き換え、にあるtostrすべての文字を削除しdeletestrます。空の文字列にすることができ、パラメータは省略することができます。fromstrtostrdeletestr

あなたは「句読点」を見ることができます:

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

詳細については、次を参照してください。


2
文字列のtranslate()およびmaketrans()メソッドは興味深いですが、このメソッドは「区切り文字で分割」(または空白)に失敗します。たとえば、「大きな洞窟がありました」は代わりに「洞窟」という単語を誤って生成します予想される「洞窟」と「内部」の…したがって、これは質問が要求することを行いません。
Eric O Lebigot

@EricLebigotがコメントしたように。上記の方法は、質問が要求することをうまく実行しません。
ジェレミーアニファク2018

2

これを実現する別の方法は、Natural Language Tool Kit(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パッケージの残りの部分で多くの楽しいことができることです。


1

まず、実際に句読点を分割関数の区切り文字として使用する意図はないと私は思います。説明では、結果の文字列から句読点を単に削除したいことを示しています。

私はかなり頻繁にこれに遭遇し、私の通常の解決策はreを必要としません。

リスト内包表記付きのワンライナーラムダ関数:

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


機能(伝統的)

従来の関数として、これは(2に加えてimport string)リスト内包表記を含む2行のみです。

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("-", " ")分割の前にハイフンをスペースに変換するためにいつでも使用できます。

ラムダまたはリスト内包なしの一般関数

より一般的な解決策(削除する文字を指定できる場合)で、リストを理解していなければ、次のようになります。

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

もちろん、常にラムダ関数を指定した文字列に一般化することもできます。


1

まず、ループでRegEx操作を実行する前に、必ずre.compile()を使用してください。これは、通常の操作よりも高速に動作するためです。

したがって、問題については、まずパターンをコンパイルしてから、それに対してアクションを実行します。

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

1

ここにいくつかの説明付きの答えがあります。

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'

または1行で、次のようにできます。

(''.join([x.replace(x, ' ') if not x.isalnum() else x for x in st])).split()

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

更新された回答


1

2つの文字列(分割されるソース文字列と区切り文字の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

1

私は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

0

@oobooと同じ問題を抱えており、このトピックを見つけました@ ghostdog74が私にインスピレーションを与えました、多分誰かが私の解決策を見つけました

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

スペースで何かを入力し、スペースで分割したくない場合は、同じ文字を使用して分割します。


単語を使用して分割する必要がある場合はどうなりますか?
Harsha Biyani

0

これが、複数のデリミタを使用した分割の私の歩みです。

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

0

以下はあなたのニーズに合う最良の答えだと思います:

\W+ このケースには適しているかもしれませんが、他のケースには適していません。

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

私は、同意\w\Wソリューションは、質問(のタイトル)への答えではありません。あなたの答えで|は、削除する必要があることに注意してください(あなたはのexpr0|expr1代わりに考えています[char0 char1…])。さらに、compile()正規表現は必要ありません。
エリックOレビゴット2014年

0

僕の見解はこちら…

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

0

私はreplace()方法が一番好きです。次の手順では、文字列で定義されたすべてのセパレータをsplitlist最初のセパレータに変更しsplitlist、その1つのセパレータでテキストを分割します。また、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]

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

0

可逆操作が必要な場合(区切り文字を保持)、この関数を使用できます。

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

0

私は最近これを行う必要がありましたが、標準ライブラリ関数と多少一致する関数が必要でしたstr.split。この関数は、0または1の引数で呼び出されたときに標準ライブラリと同じように動作します。

def split_many(string, *separators):
    if len(separators) == 0:
        return string.split()
    if len(separators) > 1:
        table = {
            ord(separator): ord(separator[0])
            for separator in separators
        }
        string = string.translate(table)
    return string.split(separators[0])

:この関数は、セパレータが単一の文字で構成されている場合にのみ役立ちます(私のユースケースと同様)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.