मैं किसी फ़ाइल की सभी पंक्तियों को कैसे निकालूं जो 6 वर्णों से कम की हो?


17

मेरे पास एक फाइल है जिसमें लगभग 10 मिलियन लाइनें हैं।

मैं फ़ाइल में सभी पंक्तियों को निकालना चाहता हूं जो छह वर्णों से कम हैं।

मैं यह कैसे करु?


क्या यह सवाल स्टैकओवरफ़्लो के लिए अधिक अनुकूल नहीं है?
user1073075

2
@ user1073075 यह पूरी तरह से यहाँ विषय पर है।
सेठ

जवाबों:


30

इसे करने के कई तरीके हैं।

का उपयोग कर grep:

grep -E '^.{6,}$' file.txt >out.txt

अब out.txtछह या अधिक वर्ण वाली रेखाएँ होंगी।

रिवर्स तरीका:

grep -vE '^.{,5}$' file.txt >out.txt

sed5 या उससे कम लंबाई वाली रेखाओं का उपयोग करना :

sed -r '/^.{,5}$/d' file.txt

रिवर्स तरीका, लंबाई छह या अधिक की छपाई लाइनें:

sed -nr '/^.{6,}$/p' file.txt 

आप का उपयोग कर एक अलग फाइल में उत्पादन को बचा सकता है >की तरह ऑपरेटर grepया संपादित यथा-स्थान का उपयोग कर फ़ाइल -iका विकल्प sed:

sed -ri.bak '/^.{6,}$/' file.txt 

मूल फ़ाइल के रूप में बैकअप किया जाएगा file.txt.bakऔर संशोधित फ़ाइल होगी file.txt

यदि आप बैकअप नहीं रखना चाहते हैं:

sed -ri '/^.{6,}$/' file.txt

शेल का उपयोग करना, धीमा करना, ऐसा न करना , यह सिर्फ एक और तरीका दिखाने के लिए है:

while IFS= read -r line; do [ "${#line}" -ge 6 ] && echo "$line"; done <file.txt

का उपयोग करते हुए python, यहां तक कि धीमी गति से grep, sed:

#!/usr/bin/env python2
with open('file.txt') as f:
    for line in f:
        if len(line.rstrip('\n')) >= 6:
            print line.rstrip('\n')

अधिक पायथोनिक होने के लिए बेहतर उपयोग सूची की समझ:

#!/usr/bin/env python2
with open('file.txt') as f:
     strip = str.rstrip
     print '\n'.join([line for line in f if len(strip(line, '\n')) >= 6]).rstrip('\n')

वाह! मैं एक अजगर जवाब के लिए उम्मीद कर रहा था =)
टेल्मेही

@DevRobot मैं देख रहा हूँ .. सूची की समझ की जाँच करें मैंने जोड़ा, अधिक पायथोनिक हो ..
हेमेयेल

1
इसके अलावा @DevRobot इतना ज़रूर नहीं है कि जब पहला विकल्प इस्तेमाल किया जाता है, तो अजगर बड़ी फ़ाइलों पर धीमा होता है। वास्तव में मुझे पूरा यकीन है कि अजगर लाखों लाइनों पर तेज होता है, क्योंकि यह प्रति पंक्ति पढ़ता है।
जैकब वलीजम

1
दूसरा पायथन उदाहरण जॉइन करने से पहले पूरी फाइल को मेमोरी में पढ़ता है। मुझे लगता है कि इस उदाहरण में पहला अजगर उदाहरण बेहतर है।
होलोले

लाइनों द्वारा पढ़ना आवश्यक रूप से धीमा है क्योंकि फाइलें इस तरह संरचित नहीं हैं। आपको वैसे भी आगे एक ब्लॉक को पढ़ने और समानांतरकरण की कम संभावनाओं के साथ एक नई खोज करने की आवश्यकता है, फिर केवल आंशिक स्ट्रिंग लौटाएं। आपको एक परिपत्र बफर की आवश्यकता है। आपको स्मृति को गतिशील रूप से आवंटित करने की आवश्यकता है यदि आपको नहीं पता है कि लाइनें कितनी लंबी हो सकती हैं।
Vee

19

यह बहुत सरल है:

grep ...... inputfile > resultfile   #There are 6 dots

यह अत्यंत कुशल है, क्योंकि grepयह जरूरत से ज्यादा पार्स करने की कोशिश नहीं करेगा, न ही किसी भी तरह से वर्णों की व्याख्या करने के लिए: यह बस एक (पूरी) पंक्ति को stdout (जो शेल फिर परिणाम को रीडायरेक्ट करता है) को भेज देता है जैसे ही वह 6 उस लाइन पर चार्ट ( .एक regexp संदर्भ में किसी भी 1 वर्ण से मेल खाता है)।

इसलिए grep केवल 6 (या अधिक) वर्ण वाली आउटपुट लाइनें होगी, और अन्य grep द्वारा आउटपुट नहीं किए जाते हैं, इसलिए वे इसे परिणामी नहीं बनाते हैं।


14

समाधान # 1: C का उपयोग करना

सबसे तेज़ तरीका: इस C प्रोग्राम को संकलित करें और चलाएं:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_BUFFER_SIZE 1000000

int main(int argc, char *argv[]) {
    int length;

    if(argc == 3)
        length = atoi(argv[2]);
    else
        return 1;

    FILE *file = fopen(argv[1], "r");

    if(file != NULL) {
        char line[MAX_BUFFER_SIZE];

        while(fgets(line, sizeof line, file) != NULL) {
            char *pos;

            if((pos = strchr(line, '\n')) != NULL)
                *pos = '\0';
            if(strlen(line) >= length)
                printf("%s\n", line);
        }

        fclose(file);
    }
    else {
        perror(argv[1]);
        return 1;
    }

    return 0;
}

के साथ संकलित करें gcc program.c -o program, ./program file line_length(जहाँ file= फ़ाइल के लिए पथ और line_length= न्यूनतम पंक्ति लंबाई, आपके मामले में)6 , अधिकतम पंक्ति की लंबाई 1000000प्रति पंक्ति वर्णों तक सीमित है ; आप इसे बदल सकते हैं MAX_BUFFER_SIZE)।

( पाया के \nसाथ स्थानापन्न करने की ट्रिक\0 यहाँ ।)

शेल समाधान को छोड़कर इस प्रश्न के लिए प्रस्तावित सभी अन्य समाधानों के साथ तुलना करें (8 वर्णों की औसत लेन के साथ 10M लाइनों के साथ ~ 91MB फ़ाइल पर परीक्षण चलाएं):

time ./foo file 6

real    0m1.592s
user    0m0.712s
sys 0m0.160s

time grep ...... file

real    0m1.945s
user    0m0.912s
sys 0m0.176s

time grep -E '^.{6,}$'

real    0m2.178s
user    0m1.124s
sys 0m0.152s

time awk 'length>=6' file

real    0m2.261s
user    0m1.228s
sys 0m0.160s

time perl -lne 'length>=6&&print' file

real    0m4.252s
user    0m3.220s
sys 0m0.164s

sed -r '/^.{,5}$/d' file >out

real    0m7.947s
user    0m7.064s
sys 0m0.120s

./script.py >out
real    0m8.154s
user    0m7.184s
sys 0m0.164s

समाधान # 2: AWK का उपयोग करना:

awk 'length>=6' file
  • length>=6: अगर length>=6 TRUE लौटाता है, तो वर्तमान रिकॉर्ड को प्रिंट करता है।

समाधान # 3: पर्ल का उपयोग करना:

perl -lne 'length>=6&&print' file
  • यदि lenght>=6TRUE लौटाता है, तो वर्तमान रिकॉर्ड को प्रिंट करता है।

% cat file
a
bb
ccc
dddd
eeeee
ffffff
ggggggg
% ./foo file 6
ffffff
ggggggg
% awk 'length>=6' file   
ffffff
ggggggg
% perl -lne 'length>=6&&print' file
ffffff
ggggggg

1
मेरा विश्वास awk
करो..मैं

2
@heemayl और मैंने तुरंत सवाल नहीं देखा, इसलिए मुझे पता था कि अगर आप ऑनलाइन होते तो आप और तेज़ होते। मेरे sedसमाधान को हटाना पड़ा (ऐसा होता है, मुझे पता है)। XD
कोस

posचर का बिंदु क्या है ? मुझे लगता है कि यह lineएक नई चरित्र के साथ चरित्र को एक पॉइंटर देता है , लेकिन आप इसका उपयोग कभी नहीं करते हैं। और अगर आपको यह नहीं मिलता है, तो आप इसे इसके बराबर सेट करते हैं \0
user1717828

@ user1717828 यदि मुझे यह मिल जाए तो मैं इसे बदल देता हूं \0( strchr()यदि चरित्र नहीं मिला है तो एक पूर्ण सूचक देता है )। बिंदु प्रत्येक पंक्ति के अंत में प्रत्येक नई पंक्ति की जगह ले रहा है \0ताकि नई रेखा को कभी भी गिना न जाए strlen(): यह इसलिए है ताकि अंतिम पंक्ति पर संभावित लापता नई रेखा की परवाह किए बिना हमेशा 6 की तुलना की जा सके। अलग तरह से केवल अंतिम पंक्ति का इलाज करना अधिक कुशल होगा, मुझे पता है। मैं शायद इसे बाद में अपडेट करूंगा।
कोस

1
@tripleee यह विचार एक समय की नौकरी से अधिक के लिए या यहां तक ​​कि बड़ी फ़ाइलों के लिए उपयोगी एक समाधान जोड़ने के लिए था, लेकिन : मैंने grepउसी फ़ाइल पर समाधान का परीक्षण किया और यह वास्तव में तेज़ है (शायद इसलिए strlen()कि यह सबसे अच्छा विचार नहीं है) । मैं getchar()इसके बजाय केवल पहले N वर्ण की जाँच करने के लिए लूप का उपयोग करने की कोशिश करूँगा , मुझे लगता है कि इसे दृष्टिगत रूप से सुधारना चाहिए। और हां, बफ़र की लंबाई के ऊपर कोई भी लाइन बस बफ़र की लंबाई तक कट जाती है।
कोस

2

आप पूर्व मोड में विम का उपयोग कर सकते हैं:

ex -sc 'v/\v.{6}/d' -cx file
  1. \v जादू चालू करो

  2. .{6} 6 या अधिक वर्णों वाली लाइनें ढूंढें

  3. v चयन को उल्टा करें

  4. d हटाना

  5. x सहेजें और बंद करें


1

रूबी समाधान:

$ cat input.txt                                                                                                          
abcdef
abc
abcdefghijk

$ ruby -ne 'puts $_ if $_.chomp.length() >= 6 ' < input.txt                                                              
abcdef
abcdefghijk

सरल विचार: रूबी की स्टडिन में फ़ाइल को रीडायरेक्ट करें, और स्टडिन से प्रिंट लाइन केवल अगर यह लंबाई अधिक या 6 के बराबर हो

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