मेरे पास एक फाइल है जिसमें इस तरह का डेटा है:

New York  100 2 17 12
California 200 10 8 3
Montana   50 25  3 0

मैं चाहता हूं कि राज्य का नाम एक ही क्षेत्र के रूप में माना जाए, फिर गणना करें कि क्षेत्र 2 का कितना प्रतिशत क्षेत्र 3 है, और अन्य क्षेत्रों को अनदेखा करें।

तो मैं आउटपुट होना चाहता हूँ

New York  2%
California 5%
Montana   50%

मैं इस प्रकार राज्य का नाम प्राप्त कर सकता हूं awk -F [0-9] '{print $1}'

लेकिन तब बाकी के खेत पूरी तरह से अनुपयोगी हो जाते हैं।

यदि मैं फ़ील्ड विभाजक को अकेला छोड़ दूं, तो न्यूयॉर्क और यॉर्क को अलग-अलग फ़ील्ड संख्याएँ मिलती हैं, और अन्य फ़ील्ड संख्याएँ 'एक के बाद एक' होती हैं।

क्या मैं इसे अजीब में कर सकता हूं, या क्या मुझे रूबी पर स्विच करना चाहिए, जिसे मैं थोड़ा जानता हूं?

awk
0
Leonard 27 मार्च 2020, 07:35
क्या आपके उदाहरण में सफेद स्थान सभी रिक्त वर्ण हैं या इसमें से कुछ टैब हैं? नहीं, आपको रूबी पर स्विच नहीं करना चाहिए।
 – 
Ed Morton
27 मार्च 2020, 17:32
सभी सफेद स्थान, कोई टैब नहीं।
 – 
Leonard
28 मार्च 2020, 20:40
सफेद स्थान में क्षैतिज टैब, लंबवत टैब, रिक्त स्थान, लाइनफ़ीड, फॉर्मफ़ीड इत्यादि शामिल हैं। मुझे लगता है कि आपका मतलब शायद "सभी रिक्त स्थान, कोई टैब या अन्य सफेद स्थान" नहीं है।
 – 
Ed Morton
28 मार्च 2020, 20:43
हाँ, सभी "अंतरिक्ष" चरित्र। ASCII 32. खराब नामकरण के लिए क्षमा करें
 – 
Leonard
29 मार्च 2020, 21:06
हाँ, यह कष्टप्रद और दुर्भाग्यपूर्ण है कि "रिक्त" और "स्थान" शब्दों के इतने अलग-अलग अर्थ हैं। मुझे लगता है कि blank character के संदर्भ में ASCII 32 है (अक्सर " " द्वारा कोड में दर्शाया जाता है), एक blank [:blank:] POSIX में वर्णों के सेट में से कोई भी है वर्ण वर्ग (अक्सर \b द्वारा कोड में दर्शाया जाता है) और एक space [:space:] POSIX वर्ण वर्ग (अक्सर \s द्वारा कोड में दर्शाया जाता है) में वर्णों का कोई भी सेट होता है। . देखें gnu.org/software/gawk/manual/gawk.html #ब्रैकेट-एक्सप्रेशन, उदाहरण के लिए, उन वर्ण वर्गों में वर्णों की परिभाषा के लिए।
 – 
Ed Morton
29 मार्च 2020, 21:35

3 जवाब

सबसे बढ़िया उत्तर

आप इसे awk में काफी आसानी से कर सकते हैं। चाल यह है कि पहला फ़ील्ड ढूंढें जो एक अंक से शुरू होता है ताकि आप "New York" जैसे नामों को समायोजित कर सकें। उदाहरण के लिए

awk '{
    n=0; name=""
    for(i=1;i<=NF;i++)
        if($i ~ /^[0-9]/) {
            n=i; break
        }
        else
            name=name?name" "$i:$i
    print name, $(n+1)/$n*100"%"
}' file

जहां चर n का उपयोग प्रत्येक फ़ील्ड पर लूप करके और पहले वर्ण की [0-9] से तुलना करके एक अंक से शुरू होने वाले पहले फ़ील्ड के लिए फ़ील्ड-नंबर को कैप्चर करने के लिए किया जाता है। यदि परीक्षण सत्य है, n को i पर सेट किया गया है और लूप टूट गया है, अन्यथा वर्ण फ़ील्ड को name के साथ संयोजित किया गया है.. (यह मानता है कि आपके पास संख्याओं के साथ 2 फ़ील्ड हैं)

आप बस ऊपर दी गई स्क्रिप्ट का चयन-कॉपी कर सकते हैं और फिर मध्य-माउस पेस्ट को अपनी फ़ाइल रखने वाली निर्देशिका में एक xterm में पेस्ट कर सकते हैं (अपनी डेटा फ़ाइल से मिलान करने के लिए फ़ाइल नाम बदलने के बाद) इसे अपने डेटा के साथ रखकर, आपको मिलेगा:

$ awk '{
>     n=0; name=""
>     for(i=1;i<=NF;i++)
>         if($i ~ /^[0-9]/) {
>             n=i; break
>         }
>         else
>             name=name?name" "$i:$i
>     print name, $(n+1)/$n*100"%"
> }' file
New York 2%
California 5%
Montana 50%
1
David C. Rankin 27 मार्च 2020, 07:58
क्या आप बता सकते हैं कि यह लाइन कैसे काम करती है? नाम = नाम? नाम" "$i:$i
 – 
Leonard
28 मार्च 2020, 18:08
ज़रूर, name केवल राज्य का नाम है। एक राज्य के नाम में कई शब्दों को संभालने के लिए, हम एक खाली name="" से शुरुआत करते हैं। फिर हम खेतों पर लूप करते हैं for (i = 1; i <= NF; i++)। यदि फ़ील्ड एक संख्या /^[0-9]/ से शुरू होती है, तो हमें पहला नंबर फ़ील्ड मिल गया है, अन्यथा यदि यह किसी संख्या से शुरू नहीं होता है, तो हम जानते हैं कि यह नाम का हिस्सा है और फ़ील्ड को name = name ? name" "$i : $i नाम से जोड़ दें। . test ? if_true : if_false क्लॉज को टर्नरी ऑपरेटर कहा जाता है। अगर name (मतलब खाली नहीं है) ? तो हम एक स्पेस और करंट फील्ड name" "$i जोड़ते हैं, अन्यथा सिर्फ पहले $i जोड़ें।
 – 
David C. Rankin
29 मार्च 2020, 01:10

आप अंतिम फ़ील्ड को संदर्भ बिंदु के रूप में उपयोग कर सकते हैं। पिछले चार क्षेत्रों को छोड़ने के लिए गॉक/माक की आवश्यकता है:

$ awk '{p=$(NF-2)*100/$(NF-3); NF-=4; print ($0"\t"p"%")}' file
New York   2%
California 5%
Montana    50%

और इसका पोर्टेबल विकल्प है:

awk '{p=$(NF-2)*100/$(NF-3); sub(/( +[^ ]+){4}$/,""); print ($0"\t"p"%")}' file
1
oguz ismail 27 मार्च 2020, 17:51
ठीक है, यह पीछे की ओर गिनने में बहुत चतुर है :) केवल नकारात्मक पक्ष यह है कि आप इतनी संख्या में फ़ील्ड के साथ फंस गए हैं - लेकिन आम तौर पर यह कोई समस्या नहीं है।
 – 
David C. Rankin
27 मार्च 2020, 08:03
1
जो वास्तव में मुझे परेशान करता है वह यह है कि एनएफ घटने से मानक के अनुसार अपरिभाषित परिणाम उत्पन्न होते हैं। धन्यवाद बीटीडब्ल्यू
 – 
oguz ismail
27 मार्च 2020, 08:11
क्या होगा यदि आपने NF > 5 और फिर split रिकॉर्ड को एक सरणी में इस्तेमाल किया और फिर पहले NF - 4 फ़ील्ड को नाम के रूप में और अगले 2 को प्रतिशत की गणना करने के लिए लिया? (मुझे यह मेरे पहले अनुमान से भी बेहतर लगता है)
 – 
David C. Rankin
27 मार्च 2020, 08:24
जिसके लिए NF - 4 फ़ील्ड को लूप में जोड़कर पहला फ़ील्ड बनाने की आवश्यकता होगी और इस प्रकार यह वन-लाइनर नहीं होगा। हालांकि अच्छा विचार है, अगर आप इसे वैकल्पिक समाधान के रूप में अपने उत्तर में जोड़ना चाहते हैं तो मैं निश्चित रूप से ऊपर उठूंगा
 – 
oguz ismail
27 मार्च 2020, 08:29

यह मानते हुए कि अंत में हमेशा एक निश्चित संख्या में फ़ील्ड होते हैं, आप उस जानकारी का उपयोग निम्नलिखित प्रतिलेख के अनुसार मक्खी पर फ़ील्ड को समायोजित करने के लिए कर सकते हैं:

pax> echo; printf 'New York 100 2 17 12\nCalifornia 200 10 8 3\nMontana 50 25 3 0\n' | awk '
+++> {while(NF>5){$1=$1" "$2;for(i=2;i<NF;i++){$i=$(i+1)};$NF="";NF=NF-1};print $1","$2","$3","$4}'

New York,100,2,17
California,200,10,8
Montana,50,25,3

आप , विभाजकों द्वारा देख सकते हैं कि फ़ील्ड 1 को दो क्षेत्रों New और York से जोड़ दिया गया है। उस लिपि की विस्तार से जांच कर रहे हैं:

while (NF > 5) {                 # Loop until entire name combined into field 1.
    $1 = $1" "$2                 # Join field 1 and 2.
    for (i = 2; i < NF; i++) {   # For every field 2 onward.
        $i = $(i+1)              # Copy following field to this field,
    }                            #     includes blanking last field.
    NF = NF - 1                  # Reduce field count.
}
# At this point field1 is whole name and fields 2-5 are values.
0
paxdiablo 27 मार्च 2020, 07:55