Textfile से स्ट्रिंग को विभाजित करने की तेज़ विधि?


11

मेरे पास दो टेक्स्ट फाइलें हैं: string.txt और lengths.txt

String.txt:

abcdefghijklmnopqrstuvwxyz

lengths.txt

5
4
10
7

मैं फाइल प्राप्त करना चाहता हूं

>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz

मैं लगभग 28,000 प्रविष्टियों के साथ काम कर रहा हूं और वे 200 और 56,000 वर्णों के बीच भिन्न हैं।

फिलहाल, मैं उपयोग कर रहा हूं:

start=1
end=0
i=0
while read read_l
do
    let i=i+1
    let end=end+read_l
    echo -e ">Entry_$i" >>outfile.txt
    echo "$(cut -c$start-$end String.txt)" >>outfile.txt
    let start=start+read_l
    echo $i
done <lengths.txt

लेकिन यह बहुत अक्षम है। कोई बेहतर विचार?


कैसे के बारे में str="$(cat string.txt)"; i=0; while read j; do echo "${file:$i:$j}"; i=$((i+j)); done <length.txt.. उपवास के रूप में काफी तेजी से केवल शेल द्वारा किया जाता है ..
heemayl

यह ईमानदार होने के लिए बहुत तेज़ नहीं है। अभी भी काफी समय लग रहा है। मैं लिनक्स / प्रोग्रामिंग के लिए काफी नया हूं, अगर आपको लगता है कि शेल का उपयोग न करके एक तेज विधि है, तो मैं विचारों के लिए खुला हूं।
user3891532

4
कोशिश करो { while read l<&3; do head -c"$l"; echo; done 3<lengths.txt; } <String.txt
जिमीज

@ जिमीज, एक जवाब में कैसे चिपके रहते हैं
इरुवर

जवाबों:


7

तुम कर सकते हो

{
  while read l<&3; do
    {
      head -c"$l"
      echo
    } 3<&-
  done 3<lengths.txt
} <String.txt

इसके लिए कुछ स्पष्टीकरण की आवश्यकता है:

मुख्य विचार का उपयोग करना है { head ; } <fileऔर इसे कम करके आंका गया है @mikeserv उत्तर । हालांकि इस मामले में हमें कई headएस का उपयोग करने की आवश्यकता है , इसलिए whileलूप पेश किया जाता है और फाइल डिस्क्रिप्टर के साथ थोड़ा सा ट्विकिंग किया जाता है ताकि headदोनों फाइलों से इनपुट पास किया जा सके ( String.txtफाइल को प्रोसेस करने के लिए एक मुख्य फाइल के length.txtरूप में और -cविकल्प से तर्क के रूप में लाइनें ) । विचार यह है कि गति में लाभ की आवश्यकता String.txtहर उस समय की तलाश से नहीं होनी चाहिए , जैसे कि एक आदेश headया cutआह्वान किया जाता है। echoबस प्रत्येक यात्रा के बाद न्यू लाइन मुद्रित करने के लिए है।

कितना तेज है (यदि कोई है) और >Entry_iलाइनों के बीच जोड़ना एक अभ्यास के रूप में छोड़ दिया जाता है।


I / O पुनर्निर्देशन का नीट उपयोग। चूंकि टैग लिनक्स है, आप यथोचित मान सकते हैं कि शेल बैश है और read -u 3डिस्क्रिप्टर 3 से पढ़ने के लिए उपयोग किया जाता है
जोनाथन लेफ़लर

@JonathanLeffler, लिनक्स के साथ बहुत कम है bash। लिनक्स-आधारित सिस्टम का सबसे बड़ा हिस्सा bashस्थापित नहीं हुआ है (एंड्रॉइड और अन्य एम्बेडेड सिस्टम लगता है)। bash, सभी की सबसे धीमी खोल जा रहा है बैश का उपयोग करने जा होगा संभावना नीचा प्रदर्शन अधिक महत्वपूर्ण से थोड़ा लाभ है कि से स्विच read <&3करने के लिए read -u3हो सकता है लाने (जो किसी भी मामले में नगण्य की तरह एक बाहरी कमांड चलाने की लागत की तुलना में किया जाएगा head)। Ksh93 पर स्विच करना, जिसमें बिल्डिन है head(और जो गैर-मानक -cविकल्प का समर्थन करता है ) प्रदर्शन को बहुत अधिक सुधार देगा।
स्टीफन चेज़लस

ध्यान दें कि head -c( headगैर-मानक विकल्प के कार्यान्वयन के लिए) का तर्क कई प्रकार के बाइट्स है, वर्ण नहीं। इससे बहु-बाइट स्थानों में अंतर होगा।
स्टीफन चेज़लस

7

आम तौर पर, आप टेक्स्ट को प्रोसेस करने के लिए शेल लूप का उपयोग नहीं करना चाहते हैं । यहां मैं उपयोग करूंगा perl:

$ perl -lpe 'read STDIN,$_,$_; print ">Entry_" . ++$n' lengths.txt < string.txt
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz

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

( -Cविकल्प जोड़ें यदि बाइट्स की संख्या के विपरीत वर्तमान लोकेल में उन नंबरों के अक्षर होने चाहिए, जैसे आपके नमूने में ASCII वर्णों के लिए, इससे कोई फर्क नहीं पड़ेगा)।


यह $_आउटपुट और इनपुट पैरामीटर दोनों के रूप में एक जटिल पुन: उपयोग है read, लेकिन यह स्क्रिप्ट में बाइट की संख्या को कम करता है।
जोनाथन लेफ्लर

एक त्वरित परीक्षण में (ओपी के नमूने ने 100000 बार दोहराया), मुझे लगता है कि यह समाधान @ जिमीज के रूप में ( 1200 सेकंड बनाम 6 मिनट ( bash, 16 सेकंड के साथ PATH=/opt/ast/bin:$PATH ksh93)) के रूप में लगभग 1200 गुना तेज है ।
स्टीफन चेज़लस

6

बैश, संस्करण 4

mapfile -t lengths <lengths.txt
string=$(< String.txt)
i=0 
n=0
for len in "${lengths[@]}"; do
    echo ">Entry_$((++n))"
    echo "${string:i:len}"
    ((i+=len))
done

उत्पादन

>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz

4

किस बारे में awk?

process.awkइस कोड के साथ एक फाइल बनाएं :

function idx(i1, v1, i2, v2)
{
     # numerical index comparison, ascending order
     return (i1 - i2)
}
FNR==NR { a[FNR]=$0; next }
{ i=1;PROCINFO["sorted_in"] = "idx";
        for (j in a) {
                print ">Entry"j;
                ms=substr($0, i,a[j])
                print ms
                i=i+length(ms)
        }
}

इसे सहेजें और निष्पादित करें awk -f process.awk lengths.txt string.txt


के उपयोग के आधार पर PROCINFO, यह मानक नहीं है awk, लेकिन gawk। उस स्थिति में मैं एक और gawkएकमात्र सुविधा पसंद करूंगा FIELDWIDTHS:awk -vFIELDWIDTHS="$(tr '\n' ' ' < lengths.txt)" '{for(i=1;i<=NF;i++)print">Entry"i ORS$i}' string.txt
मैनटवर्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.