केवल उन रेखाओं को रखें जिनमें सीमांकक की सटीक संख्या हो


9

मेरे पास एक बड़ी सीएसएसवी फाइल है जिसमें 10 फ़ील्ड कॉमा द्वारा अलग किए गए हैं। दुर्भाग्य से, कुछ पंक्तियाँ विकृत हैं और इसमें ठीक 10 अल्पविराम नहीं हैं (जब मैं आर में फाइल पढ़ना चाहता हूँ तो कुछ समस्याएं पैदा होती हैं)। मैं केवल उन पंक्तियों को कैसे फ़िल्टर कर सकता हूं जिनमें वास्तव में 10 अल्पविराम हैं?


1
आपका प्रश्न और जुड़ा हुआ प्रश्न समान प्रश्न नहीं हैं । आप पूछते हैं कि एक निश्चित संख्या से अधिक या कम संख्या वाली लाइनों को कैसे संभालना है, जबकि उस प्रश्न के लिए केवल एक न्यूनतम मिलान संख्या की आवश्यकता होती है। वास्तविकता यह है कि इस प्रश्न का उत्तर आसानी से दिया जाता है - इसमें पूर्ण रूप से एक पंक्ति को स्कैन करने की आवश्यकता नहीं होती है, या (कम से कम, जैसा कि sedयहां होता है) केवल जहां तक ​​एक से अधिक मिलान की तलाश की जाती है, हालांकि यह प्रश्न करता है। आपको इसे बंद नहीं करना चाहिए था।
15

1
वास्तव में, करीब की तलाश में, प्रश्नकर्ता वहाँ है चाहता हूँ कोई और अधिक या कम से कम मैचों। उस सवाल को एक नए शीर्षक की जरूरत है। लेकिन इस grepसवाल का कोई स्वीकार्य जवाब नहीं है ...
mikeserv

जवाबों:


21

एक और पोसिक्स एक:

awk -F , 'NF == 11' <file

यदि रेखा में 10 अल्पविराम हैं, तो इस रेखा में 11 क्षेत्र होंगे। इसलिए हम केवल क्षेत्र परिसीमन के रूप में awkउपयोग करते हैं ,। यदि फ़ील्ड की संख्या 11 है, तो स्थिति NF == 11सत्य है, awkफिर डिफ़ॉल्ट कार्रवाई करता है print $0


5
यह वास्तव में पहली बात है जो इस सवाल पर मेरे दिमाग में आई। मुझे लगा कि यह ओवरकिल है, लेकिन कोड को देखकर ... यह स्पष्ट है कि स्पष्ट है। दूसरों के लाभ के लिए: -Fफ़ील्ड विभाजक सेट NFकरता है और किसी दिए गए पंक्ति में फ़ील्ड की संख्या को संदर्भित करता है। चूंकि कोई कोड ब्लॉक {statement}स्थिति में जोड़ा नहीं जाता है NF == 11, इसलिए डिफ़ॉल्ट कार्रवाई लाइन प्रिंट करना है। (@cuonglm, यदि आप चाहें तो इस स्पष्टीकरण को शामिल करने के लिए स्वतंत्र महसूस करें।)
वाइल्डकार्ड

4
+1: बहुत सुंदर और पठनीय समाधान जो बहुत सामान्य है। मैं उदाहरण के लिएawk -F , 'NF != 11' <file
Miroslav Sabo

@ गर्डहेड: इसे प्राप्त करना आसान है, जैसा कि आप ओपी ने अपनी टिप्पणी में कहा है। मैं अपने मोबाइल से कभी-कभी उत्तर देता हूं, इसलिए विवरण विवरण जोड़ना मुश्किल है।
कोउंगलम

1
@mikeserv: नहीं, क्षमा करें यदि मैंने आपको भ्रमित किया है, तो यह सिर्फ मेरी बुरी अंग्रेजी है। आपके पास 1-9 कॉमा के साथ 11 फ़ील्ड नहीं हो सकते।
कोउंगलम

1
@OlivierDulac: यह आपको फ़ाइल के साथ गार्ड के साथ शुरू -या नाम देता है -
cuonglm

8

का उपयोग कर egrep(या grep -EPOSIX में):

egrep "^([^,]*,){10}[^,]*$" file.csv

यह 10 कॉमा से युक्त कुछ भी नहीं फ़िल्टर करता है: यह पूर्ण लाइनों ( ^शुरुआत में और $अंत में) से मेल खाता है , जिसमें {10}अनुक्रम के दस पुनरावृत्ति ( ) के अलावा "वर्णों के किसी भी संख्या ',', के बाद एकल ',' ' ( ([^,]*,)), इसके बाद ',' ( [^,]*) को छोड़कर किसी भी संख्या में वर्ण ।

आप -xएंकर को छोड़ने के लिए पैरामीटर का उपयोग भी कर सकते हैं :

grep -xE "([^,]*,){10}[^,]*" file.csv

यह कम से कम कुशल है cuonglm के awkसमाधान हालांकि; उत्तरार्द्ध आमतौर पर लगभग 10 कॉमा के साथ लाइनों के लिए मेरे सिस्टम पर छह गुना तेज होता है। लंबी लाइनों के कारण बड़ी मंदी होगी।


5

सबसे सरल grepकोड जो काम करेगा:

grep -xE '([^,]*,){10}[^,]*'

स्पष्टीकरण:

-xयह सुनिश्चित करता है कि पैटर्न पूरे भाग से मेल खाए , बजाय इसके भाग के। यह महत्वपूर्ण है ताकि आप 10 से अधिक कॉमा के साथ लाइनों से मेल न खाएं।

-E "विस्तारित रेगेक्स" का अर्थ है, जो आपके रेगेक्स में कम बैकस्लैश-बचने के लिए बनाता है।

कोष्ठक का उपयोग समूह बनाने के लिए किया जाता है, और {10}बाद में इसका मतलब है कि परांठे के भीतर पैटर्न की एक पंक्ति में ठीक दस मैच होने चाहिए।

[^,]एक वर्ण वर्ग है- उदाहरण के लिए, [c-f]किसी भी एकल वर्ण से मेल खाएगा जो एक c, एक d, eया एक है f, और [^A-Z]किसी भी एकल वर्ण से मेल खाएगा जो एक अपरकेस अक्षर नहीं है। इसलिए [^,]कॉमा को छोड़कर किसी भी एकल वर्ण से मेल खाता है।

*चरित्र वर्ग साधन के बाद "शून्य या इनमें से अधिक।"

तो रेगेक्स भाग का ([^,]*,)अर्थ है "किसी भी वर्ण को छोड़कर कोई भी संख्या (शून्य काल सहित), इसके बाद अल्पविराम" और {10}इनमें से 10 निर्दिष्ट करता है। फिर [^,]*बाकी गैर-अल्पविराम वर्णों को पंक्ति के अंत तक मिलान करने के लिए।


5
sed -ne's/,//11;t' -e's/,/&/10p' <in >out

वह पहले 11 या अधिक अल्पविरामों के साथ किसी भी पंक्ति को बाहर निकालता है, और फिर जो केवल 10 अल्पविराम से मेल खाता है, उसके प्रिंट।

जाहिर है कि मैंने पहले इस जवाब ... यहाँ एक है मुझे-साहित्यिक चोरी एक सवाल कुछ पैटर्न का सटीक रूप से 4 घटनाओं की तलाश में से:

आप केवल कमांड को जोड़कर [num]एक sed s///ubsteration कमांड के साथ एक पैटर्न की घटना को लक्षित कर सकते हैं [num]। जब आप tएक सफल प्रतिस्थापन के लिए स्थापन करते हैं और लक्ष्य :लेबल को निर्दिष्ट नहीं करते हैं , tतो स्क्रिप्ट से बाहर की शाखाएँ। इसका मतलब है कि आपको बस इतना करना है s///5या अधिक अल्पविराम के लिए परीक्षण करना है , फिर जो शेष है उसे प्रिंट करें।

या, कम से कम, यह उन पंक्तियों को संभालता है जो आपकी अधिकतम 4 से अधिक है। जाहिर है आपके पास न्यूनतम आवश्यकता भी है। सौभाग्य से, यह उतना ही सरल है:

sed -ne 's|,||5;t' -e 's||,|4p'

... बस ,अपने साथ एक लाइन पर 4 वीं घटना की जगह लें और ubstocation के झंडे pपर अपने s///रिंट का सामना करें । क्योंकि ,5 या अधिक बार मिलान करने वाली कोई भी रेखा पहले ही छंट चुकी होती है, 4 ,मैचों वाली रेखाओं में केवल 4 होते हैं ।


1
@cuonglm - यह वही है जो वास्तव में, पहले था, लेकिन लोग हमेशा मुझे बता रहे हैं कि मुझे अधिक पठनीय कोड लिखना चाहिए। चूँकि मैं पढ़ सकता हूँ कि सामान दूसरों के विवाद के रूप में अपठनीय im सुनिश्चित नहीं है कि क्या रखा जाए और क्या गिरा जाए ...? इसलिए मैंने दूसरा अल्पविराम लगाया।
15

@ cuonglm - आप मेरा मजाक उड़ा सकते हैं - इससे मेरी भावनाओं को ठेस नहीं पहुंचेगी। मैं मजाक कर सकता हूं। अगर तुम मेरा मजाक उड़ा रहे थे तो यह थोड़ा मजाकिया था। ठीक है - मुझे यकीन नहीं था और मैं जानना चाहता था। मेरी राय में, लोगों को खुद पर हंसने में सक्षम होना चाहिए। वैसे भी, मैं अभी भी नहीं मिलता है!
15

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

यह दिलचस्प है कि इस जवाब में , अगर मैं s/hello/world/2साथ s//world/2काम करता हूं, तो जीएनयू सेड ठीक काम करता है। हेरलूम sedसे दो के साथ , /usr/5bin/posix/sedसिगफॉल्ट उठाएं, /usr/5bin/sedअसीम लूप में जाता है।
congonglm

@mikeserv, के संदर्भ में के बारे में हमारे पहले चर्चा sedऔरawk इस जवाब की तरह (टिप्पणी में) मैं और यह upvoted, लेकिन नोटिस स्वीकार किए जाते हैं का अनुवाद awkहै इस सवाल का जवाब: "11 क्षेत्रों के साथ लाइनों प्रिंट" और इस का अनुवाद sedजवाब है: " 11 वीं अल्पविराम को हटाने का प्रयास करें। यदि आप असफल होते हैं तो अगली पंक्ति पर जाएं। 10 वीं अल्पविराम को स्वयं के साथ बदलने का प्रयास करें; यदि आप सफल होते हैं तो पंक्ति को प्रिंट करें। " awkजवाब कंप्यूटर के लिए दिए गए निर्देशों का अभी जिस तरह तुम उन्हें अंग्रेजी में व्यक्त होता देता है। ( awkक्षेत्र आधारित डेटा के लिए अच्छा है।)
वाइल्डकार्ड

4

कुछ कम फेंकना python:

#!/usr/bin/env python2
with open('file.csv') as f:
    print '\n'.join(line for line in f if line.count(',') == 10)

यह प्रत्येक पंक्ति को पढ़ेगा और जाँच करेगा कि क्या लाइन में अल्पविरामों की संख्या 10 के बराबर है line.count(',') == 10, यदि ऐसा है तो वह रेखा को प्रिंट करेगा।


2

और यहाँ एक पर्ल तरीका है:

perl -F, -ane 'print if $#F==10'

इसके इनपुट फ़ाइल लाइन को लाइन से पढ़ने और प्रत्येक लाइन पर दी गई स्क्रिप्ट को निष्पादित करने का -nकारण बनता perlहै -e-aस्वत: बंटवारे पर बदल जाता है: प्रत्येक इनपुट लाइन द्वारा दिए गए मूल्य पर विभाजित किया जाएगा -F(यहाँ, एक अल्पविराम) और सरणी के रूप में सहेजा @F

$#F(या अधिक सामान्य रूप से $#array), सरणी के उच्चतम सूचकांक है @F। चूंकि सरणियाँ शुरू होती हैं 0, 11 क्षेत्रों वाली एक पंक्ति में एक @Fका होगा 10। लिपि, लिपि को रेखा से हटाती है यदि उसके ठीक 11 क्षेत्र हों।


आप print if @F==11स्केलर के संदर्भ में एक सरणी के रूप में भी कर सकते हैं जो तत्वों की संख्या लौटाता है।
सोब्रीक

1

यदि फ़ील्ड में अल्पविराम हो सकते हैं या आपके कोड को सीएसवी समझने की आवश्यकता होती है । उदाहरण (तीन स्तंभों के साथ):

$ cat filter.csv
a,b,c
d,"e,f",g
1,2,3,4
one,two,"three
...continued"

$ cat filter.csv | python3 -c 'import sys, csv
> csv.writer(sys.stdout).writerows(
> row for row in csv.reader(sys.stdin) if len(row) == 3)
> '
a,b,c
d,"e,f",g
one,two,"three
...continued"

मुझे लगता है कि अब तक के अधिकांश समाधान दूसरी और चौथी पंक्ति को छोड़ देंगे।

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