कई शब्द सीमा सीमांकक के साथ शब्दों में विभाजित स्ट्रिंग्स


671

मुझे लगता है कि मैं जो करना चाहता हूं वह काफी सामान्य कार्य है लेकिन मुझे वेब पर कोई संदर्भ नहीं मिला है। मेरे पास विराम चिह्न के साथ पाठ है, और मुझे शब्दों की एक सूची चाहिए।

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

होना चाहिए

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

लेकिन पायथन str.split()केवल एक तर्क के साथ काम करता है, इसलिए मेरे पास व्हाट्सएप के साथ विभाजन के बाद विराम चिह्न के साथ सभी शब्द हैं। कोई विचार?



6
अजगर str.split()भी बिना किसी तर्क के काम करता है
इवान विनोग्रादोव

जवाबों:


468

एक मामला जहां नियमित रूप से उचित ठहराया जाता है:

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

29
नियमित अभिव्यक्ति पहली बार में कठिन हो सकती है, लेकिन बहुत शक्तिशाली हैं। नियमित अभिव्यक्ति '\ w +' का अर्थ है "एक शब्द चरित्र (az आदि) एक या अधिक बार दोहराया"। यहाँ पायथन नियमित भावों पर एक HOWTO है: amk.ca/python/howto/regex
RichieHindle

324
यह सवाल का जवाब नहीं है। यह एक अलग सवाल का जवाब है, जो इस विशेष स्थिति के लिए काम करता है। यह ऐसा है जैसे किसी ने पूछा "मैं बाएं मोड़ को कैसे बनाऊं" और शीर्ष-मतदान का जवाब था "अगले तीन दाएं मुड़ें।" यह कुछ चौराहों के लिए काम करता है, लेकिन यह आवश्यक जवाब नहीं देता है। विडंबना यह है कि इस सवाल का जवाब है में re, बस नहीं findall। नीचे दिए गए उत्तर re.split()बेहतर है।
जेसी ढिल्लन

4
@JesseDhillon "सभी वर्णों को शब्द वर्णों के अनुक्रम से युक्त करते हैं" और "गैर-शब्द वर्णों के अनुक्रम से युक्त सभी सब्सट्रिंग्स पर विभाजन" शाब्दिक रूप से एक ही ऑपरेशन को व्यक्त करने के अलग-अलग तरीके हैं; मुझे यकीन नहीं है कि आप या तो बेहतर जवाब देंगे।
मार्क अमेरी जूल

4
@TMWP: apostophe का मतलब है कि एक शब्द की तरह don't, एक शब्द के रूप में व्यवहार किया जाता है बल्कि में विभाजित होने से donऔर t
रिचीइंडल

574

re.split ()

re.plplit (पैटर्न, स्ट्रिंग [, मैक्ससिलेट = 0])

पैटर्न की घटनाओं से स्ट्रिंग विभाजित करें। यदि कोष्ठक पर कब्जा पैटर्न में उपयोग किया जाता है, तो पैटर्न में सभी समूहों के पाठ को भी परिणामी सूची के हिस्से के रूप में वापस किया जाता है। यदि मैक्सप्लिट नॉनज़ेरो है, तो अधिकांश मैक्सप्लिट स्प्लिट में होते हैं, और स्ट्रिंग के शेष को सूची के अंतिम तत्व के रूप में वापस किया जाता है। (असंगतता पर ध्यान दें: मूल पायथन 1.5 रिलीज में, मैक्सप्लिट को नजरअंदाज कर दिया गया था। यह बाद के रिलीज में तय किया गया है।)

>>> 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
इस समाधान का फायदा यह है कि आसानी से अंडरस्कोर पर भी विभाजित होने के लिए अनुकूलित किया जा सकता है, कुछ हल नहीं करता है: प्रिंट re.split ("\ W + | _", "परीक्षण this_thing") 'पैदावार: [' परीक्षण ',' यह ' , 'बात']
एमिल स्टेनस्ट्रॉम्

63
अब केवल अगर मैं के बीच अंतर याद कर सकता है \w, \W, \s, और \S। जो किसी ने सोचा था कि एक ध्वज के पूंजीकरण को इसके अर्थ को उलटना चाहिए, इसे सिर के माध्यम से गोली मारनी होगी।
ArtOfWarfare

1
स्ट्रिंग स्प्लिटिंग का एक सामान्य उपयोग अंतिम परिणाम से रिक्त स्ट्रिंग प्रविष्टियों को हटा रहा है। क्या इस विधि से ऐसा करना संभव है? re.split ('\ W +', 'abc') परिणाम ['', 'a', 'b', 'c', '']
स्कॉट Morken

3
@ArtOfWarfare shiftकुछ का विपरीत करने के लिए कुंजी का उपयोग करना आम है। ctrl+zपूर्ववत करें बनाम ctrl+shift+zफिर से करें। तो shift w, या W, इसके विपरीत होगा w
फ्रैंक वेल

1
यह उत्तर शीर्ष पर होना चाहिए - यह एकमात्र ऐसा है जो प्रश्न शीर्षक का सटीक उत्तर देता है।
Kranach

381

रीजैक्स के बिना ऐसा करने का एक और त्वरित तरीका है, नीचे दिए गए पात्रों को पहले बदलना:

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

71
मेरे मामले के लिए त्वरित और गंदे लेकिन एकदम सही (मेरे विभाजक एक छोटे, ज्ञात सेट थे)
एंडी बेकर

7
उस मामले के लिए बिल्कुल सही, जहां आपके पास आरई लाइब्रेरी तक पहुंच नहीं है, जैसे कि कुछ छोटे माइक्रोकंट्रोलर। :-)
tu-Reinstate Monica-dor duh

11
मुझे लगता है कि यह आरई की तुलना में अधिक स्पष्ट है, इसलिए यह एक तरह से नॉब फ्रेंडली है। कभी-कभी सब कुछ करने के लिए सामान्य समाधान की आवश्यकता नहीं होती है
एडम ह्यूजेस

बहुत बढ़िया। मेरे पास एक मल्टीपल इनपुट स्थिति में एक .split () था, और जब उपयोगकर्ता, मुझे, इनपुट को एक स्थान और एक अल्पविराम से अलग करने के लिए पकड़ने की आवश्यकता होती थी। मैं फिर से हार मानने और पीछे हटने वाला था, लेकिन आपके (.replace) समाधान ने सिर पर कील ठोक दी। धन्यवाद।
JayJay123

जब आप रिक्त स्थान पर विभाजित नहीं करना चाहते हैं और आप अन्य वर्णों पर विभाजित करना चाहते हैं तो यह आपको गलत उत्तर देगा।
अहमद

307

इतने सारे उत्तर, फिर भी मुझे कोई समाधान नहीं मिल रहा है जो कुशलता से पूछे जाने वाले प्रश्नों का शीर्षक क्या कहता है (कई संभावित विभाजकों पर विभाजन - इसके बजाय, कई उत्तर किसी भी चीज पर विभाजित होते हैं जो एक शब्द नहीं है, जो अलग है)। तो यहाँ शीर्षक में सवाल का जवाब है, जो पायथन के मानक और कुशल 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()ठीक "कई विभाजकों के साथ विभाजन" है, जैसा कि प्रश्न शीर्षक में पूछा गया है।

यह समाधान इसके अलावा कुछ अन्य समाधानों में पाए गए शब्दों में गैर-एएससीआईआई पात्रों के साथ समस्याओं के लिए प्रतिरक्षा है ( भूतडॉग74 के उत्तर के लिए पहली टिप्पणी देखें )।

reमॉड्यूल और अधिक कुशल (गति और कटाई में) अजगर छोरों और परीक्षण "हाथ से" कर की तुलना में है!


3
"मैं कोई समाधान नहीं ढूंढ सकता जो कुशलता से करता है कि प्रश्नों का शीर्षक शाब्दिक रूप से क्या पूछता है" - दूसरा जवाब यह है कि, 5 साल पहले पोस्ट किया गया: stackoverflow.com/a/1059601/2642204
बार्टोज़केपी

17
यह उत्तर सीमांकक (कई सीमांकक के एक सेट से) में विभाजित नहीं होता है: यह बदले में कुछ भी पर विभाजन करता है जो अल्फ़ान्यूमेरिक नहीं है। उन्होंने कहा, मैं मानता हूं कि मूल पोस्टर का आशय शायद कुछ विराम चिह्नों को हटाने के बजाय केवल शब्दों को रखना है।
एरिक ओ लेबिगॉट

EOL: मुझे लगता है कि यह उत्तर कई डेलमीटर के सेट पर विभाजित होता है। यदि आप गैर-अल्फ़ान्यूमेरिक्स को स्ट्रिंग में जोड़ते हैं जो निर्दिष्ट नहीं हैं, तो अंडरस्कोर की तरह, वे विभाजित नहीं हैं, जैसा कि अपेक्षित था।
गुरुत्वाकर्षण काल

@ ग्रेविवेल: मुझे यकीन नहीं है कि मैं समझता हूं: क्या आप एक ठोस उदाहरण दे सकते हैं?
एरिक ओ लेबिगॉट

3
@ ईओएल: मुझे सिर्फ एहसास हुआ कि मैं आपकी टिप्पणी से भ्रमित था "यह उत्तर विभाजित नहीं होता है ..." मुझे लगा कि यह "आपके" पुनःप्रकाश उत्तर को संदर्भित करता है, लेकिन मुझे अब एहसास हुआ कि आपका मतलब है जिमल का जवाब। मुझे लगता है कि यह उत्तर (जिस पर मैं टिप्पणी कर रहा हूं) का उत्तर सबसे अच्छा है :)
ग्रेविटीवैल

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

यदि आवश्यक हो तो पात्रों के लिए यूनिकोड सम्मेलनों को स्वीकार करने के लिए नियमित अभिव्यक्ति पुस्तकालय बनाया जा सकता है। इसके अतिरिक्त, यह एक ही समस्या का उपयोग करने के लिए स्वीकृत समाधान है: जैसा कि अब है, यह एपोस्ट्रोफ पर विभाजित होता है। आप चाहते हैं o for o in s if (o in not string.punctuation or o == "'"), लेकिन फिर एक लाइनर के लिए यह बहुत जटिल हो सकता है अगर हम cedbeu के पैच में भी जोड़ते हैं।
डैनियल एच।

यहाँ एक और मुद्दा है। यहां तक ​​कि जब हम @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']
स्टीफन वैन डेन अककर

4
यह समाधान बहुत ही अयोग्य है: पहले सूची को व्यक्तिगत वर्णों में बदल दिया जाता है, फिर विराम चिह्नों के पूरे सेट को मूल स्ट्रिंग में प्रत्येक एकल वर्णों से गुजारा जाता है, फिर पात्रों को वापस इकट्ठा किया जाता है, और फिर फिर से विभाजित किया जाता है। यह सब "आंदोलन" एक नियमित अभिव्यक्ति-आधारित समाधान की तुलना में बहुत जटिल है: भले ही गति किसी दिए गए अनुप्रयोग में कोई फर्क नहीं पड़ता है, एक जटिल समाधान की आवश्यकता नहीं है। चूंकि reमॉड्यूल मानक है और यह दोनों को सुगमता और गति प्रदान करता है, इसलिए मैं नहीं देखता कि इसे क्यों बढ़ाया जाए।
एरिक ओ लेबिगॉट

39

प्रो-टिप: string.translateपायथन ने सबसे तेज़ स्ट्रिंग ऑपरेशन के लिए उपयोग किया है।

कुछ प्रमाण ...

सबसे पहले, धीमा तरीका (क्षमा करें 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.translate सी में लागू किया गया है और पायथन में कई स्ट्रिंग हेरफेर कार्यों के विपरीत, string.translate एक नया स्ट्रिंग का उत्पादन नहीं करता है । तो यह के रूप में उपवास के रूप में आप स्ट्रिंग प्रतिस्थापन के लिए मिल सकता है।

यह थोड़ा अजीब है, हालांकि, इस जादू को करने के लिए अनुवाद तालिका की आवश्यकता है। आप maketrans()सुविधा फ़ंक्शन के साथ अनुवाद तालिका बना सकते हैं । यहाँ उद्देश्य सभी अवांछित पात्रों को रिक्त स्थान पर अनुवाद करना है। एक एक के लिए एक स्थानापन्न। फिर से, कोई नया डेटा नहीं बनता है। तो यह उपवास है !

अगला, हम अच्छे पुराने का उपयोग करते हैं split()split()डिफ़ॉल्ट रूप से सभी व्हाट्सएप पात्रों पर काम करेगा, विभाजन के लिए उन्हें एक साथ समूहित करना। परिणाम उन शब्दों की सूची होगा जो आप चाहते हैं। और यह दृष्टिकोण लगभग 4 गुना तेज है re.findall()!


4
मैंने यहां एक परीक्षण किया, और यदि आपको यूनिकोड का उपयोग करने की आवश्यकता है, patt = re.compile(ur'\w+', re.UNICODE); patt.findall(S)तो ट्रांसलेशन का उपयोग अनुवाद की तुलना में तेज़ है, क्योंकि आपको ट्रांसफ़ॉर्म करने से पहले स्ट्रिंग को एन्कोड करना होगा, और यूनिकोड पर वापस जाने के लिए विभाजन के बाद सूची में प्रत्येक आइटम को डीकोड करना होगा।
राफेल एस। कैल्सवेरीनी

आप ट्रांसलेशन कार्यान्वयन को एक-लाइनर कर सकते हैं और यह सुनिश्चित कर सकते हैं कि S, स्प्लिटर्स के बीच नहीं है:s.translate(''.join([(chr(i) if chr(i) not in seps else seps[0]) for i in range(256)])).split(seps[0])
hobs

कुछ नहीं लिया। आप सेब और संतरे की तुलना कर रहे हैं। ;) अजगर 3 में मेरा समाधान अभी भी काम करता है; पी और बहु-चार विभाजकों के लिए समर्थन है। :) एक नए स्ट्रिंग को आवंटित किए बिना सरल तरीके से करने का प्रयास करें। :), लेकिन सच है, मेरा लक्ष्य कमांड लाइन परासन तक सीमित है और उदाहरण के लिए किताब नहीं है।
pprzemek

आप कहते हैं कि "एक नई स्ट्रिंग का उत्पादन नहीं करता है", जिसका अर्थ है कि यह दिए गए स्ट्रिंग पर कार्यस्थल पर काम करता है? मैंने इसे अब अजगर 2.7 के साथ परीक्षण किया और यह oroginal string को संशोधित नहीं करता है और नया लौटाता है।
प्रोकॉप हपाला

26

मेरे पास एक समान दुविधा थी और मैं 'पुनः' मॉड्यूल का उपयोग नहीं करना चाहता था।

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

2
reमॉड्यूल का उपयोग क्यों नहीं किया जाता है, जो तेजी से और स्पष्ट दोनों तरह से है (न कि नियमित रूप से अभिव्यक्तियां विशेष रूप से स्पष्ट हैं, लेकिन क्योंकि यह छोटा और सीधा तरीका है)?
एरिक ओ लेबिगॉट

13

सबसे पहले, मैं दूसरों से सहमत होना चाहता हूं कि रेगेक्स या 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(...)- लेकिन यदि प्रदर्शन महत्वपूर्ण है, तो बाहर रेगेक्स को संकलित करना फायदेमंद हो सकता है - मेरे उपयोग के मामले में, अंतर महत्वपूर्ण नहीं था, इसलिए मैं सादगी और पठनीयता पसंद करता हूं।

विकल्प 2 - str.replace

यह कुछ और पंक्तियाँ हैं, लेकिन इसका विस्तार होने के बिना यह जांचने का लाभ है कि क्या आपको regex में एक निश्चित चरित्र से बचने की आवश्यकता है।

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 - configools.reduce

(Python 2 में, reduceयह बिना किसी प्रकार के फंक्शंस से आयात किए बिना वैश्विक नामस्थान में उपलब्ध है।)

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

एचएम, एक अन्य विधि का उपयोग करना है str.translate- यह यूनिकोड-सक्षम नहीं है, लेकिन अन्य तरीकों की तुलना में सबसे अधिक तेजी से संभव है और जैसा कि कुछ मामलों में अच्छा हो सकता है: replacements=',-!?'; import string; my_str = my_str.translate(string.maketrans(replacements, ' ' * len(replacements)))यहां भी वर्णों की एक स्ट्रिंग के रूप में प्रतिस्थापन होना अनिवार्य है, न कि टपल या सूची।
MarSoft

@MarSoft धन्यवाद! मैंने उस उत्तर के शीर्ष पर एक का उल्लेख किया है, लेकिन इसे जोड़ने का फैसला किया क्योंकि मौजूदा उत्तर पहले से ही अच्छी तरह से चर्चा कर चुके हैं।
टेलर एड्मिस्टन

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]

फिर यह एक तीन-लाइनर बन जाता है:

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

व्याख्या

हास्केल में लिस्ट मोनाड के रूप में जाना जाता है। सन्यासी के पीछे विचार यह है कि एक बार "मोनाड में" आप "मोनाड में रहें" जब तक कि कुछ आपको बाहर नहीं ले जाता है। हास्केल में उदाहरण के लिए, कहते हैं कि आप range(n) -> [1,2,...,n]एक सूची पर अजगर फ़ंक्शन को मैप करते हैं । यदि परिणाम एक सूची है, तो यह सूची में जगह में संलग्न हो जाएगा, इसलिए आपको कुछ ऐसा मिलेगाmap(range, [3,4,1]) -> [0,1,2,0,1,2,3,0] । इसे मैप-एपेंड (या मैपेंड, या शायद ऐसा कुछ) के रूप में जाना जाता है। यहाँ विचार यह है कि आपको यह ऑपरेशन (टोकन पर बंटवारा) मिला है, और जब भी आप ऐसा करते हैं, आप परिणाम को सूची में शामिल कर लेते हैं।

आप इसे एक फ़ंक्शन में सार कर सकते हैं और tokens=string.punctuationडिफ़ॉल्ट रूप से कर सकते हैं।

इस दृष्टिकोण के लाभ:

  • यह दृष्टिकोण (भोले भाले rexx- आधारित दृष्टिकोण के विपरीत) मनमाने ढंग से लंबाई टोकन (जो regex भी अधिक उन्नत वाक्यविन्यास के साथ भी कर सकते हैं) के साथ काम कर सकता है।
  • आप केवल टोकन तक ही सीमित नहीं हैं; आपके पास प्रत्येक टोकन के स्थान पर मनमाने ढंग से तर्क हो सकते हैं, उदाहरण के लिए "टोकन" में से एक एक फ़ंक्शन हो सकता है जो नेस्टेड कोष्ठक के अनुसार विभाजित होता है।

नीट हास्केल समाधान, लेकिन आईएमओ यह पायथन में बिना मैपेंड के अधिक स्पष्ट रूप से लिखा जा सकता है।
व्लाद इम्पाला

@Goose: मुद्दा यह था कि 2-लाइन फ़ंक्शन map_then_appendका उपयोग समस्या को 2-लाइनर बनाने के लिए किया जा सकता है, साथ ही कई अन्य समस्याओं को लिखने में बहुत आसान है। अधिकांश अन्य समाधान नियमित अभिव्यक्ति reमॉड्यूल का उपयोग करते हैं , जो कि अजगर नहीं है। लेकिन मैं इस बात से नाखुश हूं कि कैसे मैं अपना जवाब असभ्य और प्रफुल्लित लगता हूं जब यह वास्तव में संक्षिप्त होता है ... मैं इसे संपादित करने जा रहा हूं ...
Ninjagecko

क्या यह पायथन में लिखित रूप में काम करने वाला है? मेरा fragmentsपरिणाम स्ट्रिंग (टोकन सहित) में पात्रों की एक सूची है।
रिक मोनिका

@ रिकेटी: यह मेरे लिए python2 और python3 दोनों में काम करता है।
निन्जाएजेको

hmmmm। शायद उदाहरण थोड़ा अस्पष्ट है। मैं जवाब में कोड की कोशिश की है होने सहित विभिन्न तरीकों के सभी प्रकार fragments = ['the,string'], fragments = 'the,string'या fragments = list('the,string')और उनमें से कोई सही उत्पादन उत्पादन कर रहे हैं।
रिक मोनिका का

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

दो बार बदलें का उपयोग करें:

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

का परिणाम:

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

4

मुझे फिर से पसंद है , लेकिन यहाँ इसके बिना मेरा समाधान है:

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

लेकिन यहाँ अधिक सुविधाजनक है।

groupby को हमारा स्ट्रिंग और फंक्शन मिलता है। यह उस फ़ंक्शन का उपयोग करने वाले समूहों में स्ट्रिंग को विभाजित करता है: जब भी फ़ंक्शन का मान बदलता है - एक नया समूह उत्पन्न होता है। तो, sep .__ समाहित है__ ठीक वैसा ही है जैसा हमें चाहिए।

groupby जोड़े का एक क्रम देता है, जहां जोड़ी [0] हमारे कार्य का एक परिणाम है और जोड़ी [1] एक समूह है। 'अगर नहीं k' का उपयोग करके हम विभाजकों के साथ समूहों को फ़िल्टर करते हैं (क्योंकि sep ._____ का परिणाम विभाजकों पर सत्य है)। खैर, यह सब है - अब हमारे पास समूहों का एक क्रम है जहां हर एक एक शब्द है (समूह वास्तव में एक चलने योग्य है इसलिए हम इसे स्ट्रिंग में बदलने के लिए शामिल होते हैं)।

यह समाधान काफी सामान्य है, क्योंकि यह एक स्ट्रिंग को अलग करने के लिए फ़ंक्शन का उपयोग करता है (आप किसी भी शर्त से विभाजित कर सकते हैं जिसकी आपको आवश्यकता है)। इसके अलावा, यह मध्यवर्ती तार / सूची नहीं बनाता है (आप शामिल हो सकते हैं और अभिव्यक्ति आलसी हो जाएगी, क्योंकि प्रत्येक समूह एक इतवार है)


4

पुन: मॉड्यूल फ़ंक्शन re.split का उपयोग करने के बजाय, आप पंडों की श्रृंखला.str.split विधि का उपयोग करके समान परिणाम प्राप्त कर सकते हैं।

सबसे पहले, उपरोक्त स्ट्रिंग के साथ एक श्रृंखला बनाएं और फिर श्रृंखला के लिए विधि लागू करें।

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

पैरामीटर पॅट सीमांकक लेता है और विभाजित स्ट्रिंग को एक सरणी के रूप में लौटाता है। यहाँ दो सीमांकक एक का उपयोग कर पारित कर रहे हैं | (या ऑपरेटर)। आउटपुट इस प्रकार है:

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


1
यह एक पूर्ण क्रिया श्रृंखला में बदलने के बाद एक साधारण कार्य करने के लिए एक पूरी लाइब्रेरी (जो मुझे पसंद है, BTW) को आयात करने के तथ्य के बजाय क्रिया की बात नहीं है। बहुत अच्छा नहीं है;
zar3bski

3

मैं खुद को पायथन के साथ फिर से परिचित कर रहा हूं और उसी चीज की जरूरत है। खोज समाधान बेहतर हो सकता है, लेकिन मैं इसके साथ आया था:

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

चतुर, को सभी अंग्रेजी व्याकरणिक निर्माणों पर काम करना चाहिए जिन्हें मैं बिना किसी रिक्त स्थान के एम-डैश को छोड़कर सोच सकता हूं - उदाहरण के लिए। (
वर्कअरेबल

3

maketrans और अनुवाद का उपयोग करके आप इसे आसानी से और बड़े करीने से कर सकते हैं

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

पायथन के
23

3

पायथन 3 में, आप PY4E से विधि का उपयोग कर सकते हैं - पायथन फॉर एवरीवन

हम स्ट्रिंग विधियों का उपयोग करके इन दोनों समस्याओं को हल कर सकते हैं lower,punctuation और translatetranslateतरीकों में से सबसे सूक्ष्म है। यहाँ के लिए प्रलेखन है translate:

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

पात्रों को बदलें fromstrवर्णों को उसी स्थिति में वर्णों के साथtostr और उन सभी वर्णों को हटा दें जो अंदर हैं deletestrfromstrऔर tostrरिक्त स्ट्रिंग हो सकता है और deletestrपैरामीटर छोड़ा जा सकता है।

आप "विराम चिह्न" देख सकते हैं:

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
स्ट्रिंग्स का अनुवाद () और maketrans () तरीके दिलचस्प हैं, लेकिन यह विधि "सीमांकक पर विभाजन" (या व्हाट्सएप) में विफल रहती है: उदाहरण के लिए, "एक बड़ी गुफा थी" जिसके बजाय "गुफा" शब्द का गलत तरीके से उत्पादन होगा। अपेक्षित "गुफा" और "इन" ... इस प्रकार, यह वह नहीं करता है जो सवाल पूछता है।
एरिक ओ लेबिगॉट

जैसे @EricLebigot ने क्या टिप्पणी की। उपरोक्त विधि वह नहीं करती है जो प्रश्न बहुत अच्छी तरह से पूछता है।
जेरेमी एनीफैक

2

इसे प्राप्त करने का दूसरा तरीका प्राकृतिक भाषा टूल किट ( 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

सबसे पहले, मुझे नहीं लगता कि आपका उद्देश्य वास्तव में विखंडन के रूप में विखंडन का उपयोग विभाजन कार्यों में करना है। आपका विवरण बताता है कि आप परिणामी तारों से विराम चिह्न को समाप्त करना चाहते हैं।

मैं इस पर बहुत बार आता हूं, और मेरे सामान्य समाधान के लिए फिर से आवश्यकता नहीं है।

वन-लाइनर लंबो फंक्शन w / लिस्ट की समझ:

(की आवश्यकता है 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("-", " ")विभाजन से पहले स्थानों में हाइफ़न को चालू करने के लिए उपयोग कर सकते हैं ।

जनरल फंक्शन w / o लैम्ब्डा या लिस्ट कॉम्प्रिहेंशन

अधिक सामान्य समाधान के लिए (जहां आप वर्णों को समाप्त करने के लिए निर्दिष्ट कर सकते हैं), और सूची समझ के बिना, आपको मिलता है:

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'

या एक पंक्ति में, हम ऐसा कर सकते हैं:

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

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

अद्यतन उत्तर


1

एक फ़ंक्शन बनाएं जो इनपुट दो स्ट्रिंग्स के रूप में लेता है (विभाजित होने के लिए स्रोत स्ट्रिंग और सीमांकक के स्प्लिटलिस्ट स्ट्रिंग) और विभाजित शब्दों की सूची को आउटपुट करता है:

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

यदि आप रिक्त स्थान पर विभाजित नहीं करना चाहते हैं तो अंतरिक्ष स्थान में कुछ इनपुट करें और उसी वर्ण का उपयोग करके विभाजित करें।


क्या होगा यदि मुझे शब्द का उपयोग करके विभाजित करना है?
हर्षा बियानी

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()नियमित अभिव्यक्ति की कोई आवश्यकता नहीं है ।
एरिक ओ लेबिगोट

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और फिर उस एक विभाजक पर पाठ को विभाजित करती है। यदि 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])

नोट : यह फ़ंक्शन केवल तब उपयोगी होता है जब आपके विभाजक एक एकल वर्ण से मिलकर होते हैं (जैसा कि मेरा usecase था)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.