จะนับจำนวนตัวอักษรในหนึ่งบรรทัดได้อย่างไรยกเว้นอักขระที่ระบุ


9

นี่คือไฟล์ส่วนหนึ่ง

N W N N N N N N N N N
N C N N N N N N N N N
N A N N N N N N N N N
N N N N N N N N N N N
N G N N N N N N N N N
N C N N N C N N N N N
N C C N N N N N N N N

ในแต่ละบรรทัดฉันต้องการนับจำนวนอักขระทั้งหมดที่ไม่ใช่ "N"

ความปรารถนาของฉันออก

1
1
1
0
1
2
2

ใช้sedเพื่อแทนที่สิ่งที่คุณไม่สนใจและawkนับความยาวที่เหลืออยู่sed 's/N//g ; s/\s//g' file | awk '{ print length($0); }'
Rolf

คำตอบ:


13

GNU awk solution:

awk -v FPAT='[^N[:space:]]' '{ print NF }' file
  • FPAT='[^N[:space:]]'- รูปแบบการกำหนดค่าของฟิลด์ (ตัวอักษรใด ๆ ยกเว้นNถ่านและช่องว่าง)

ผลลัพธ์ที่คาดหวัง:

1
1
1
0
1
2
2


7

สมมติว่าจำเป็นต้องมีการนับสำหรับแต่ละบรรทัดนอกเหนือจากอักขระช่องว่างและ N

$ perl -lne 'print tr/N //c' ip.txt 
1
1
1
0
1
2
2
  • ค่าส่งคืนของtrคือจำนวนอักขระที่ถูกแทนที่
  • c เพื่อเติมเต็มชุดของอักขระที่กำหนด
  • สังเกตการใช้-lตัวเลือกตัดอักขระขึ้นบรรทัดใหม่จากบรรทัดอินพุตเพื่อหลีกเลี่ยงข้อผิดพลาดแบบออฟไลน์และเพิ่มอักขระขึ้นบรรทัดใหม่สำหรับคำสั่งพิมพ์


ทางออกทั่วไปมากขึ้น

perl -lane 'print scalar grep {$_ ne "N"} @F' ip.txt 
  • -aตัวเลือกเพื่อแยกบรรทัดอินพุตโดยอัตโนมัติในพื้นที่สีขาวบันทึกใน@Fอาร์เรย์
  • grep {$_ ne "N"} @Fส่งคืนอาร์เรย์ขององค์ประกอบทั้งหมด@Fที่ไม่ตรงกับสตริงN
    • regex เทียบเท่าจะเป็น grep {!/^N$/} @F
  • การใช้scalarจะให้จำนวนองค์ประกอบของอาร์เรย์

6

โซลูชันawkทางเลือก:

awk '{ print gsub(/[^N[:space:]]/,"") }' file
  • gsub(...)- gsub()ฟังก์ชั่นคืนค่าจำนวนของการทดแทนที่ทำ

ผลลัพธ์:

1
1
1
0
1
2
2

6

awkวิธีอื่น(จะคืนค่า -1สำหรับบรรทัดว่าง)

awk -F'[^N ]' '$0=NF-1""' infile

หรือในคอมเพล็กซ์ก็จะส่งคืน-1ในบรรทัดว่างเปล่า0ในช่องว่าง (แท็บ / ช่องว่าง) เท่านั้น

awk -F'[^N \t]+' '$0=NF-1""' infile

จะพิมพ์-1สำหรับบรรทัดว่างเปล่า ... แต่จากนั้นอาจเป็นที่พึงประสงค์ในการแยกบรรทัดที่สร้างจาก N / space และบรรทัดว่างเปล่าเท่านั้น ...
Sundeep

1
@Sundeep ใช่ถูกต้องแล้ว โปรดดูการอัปเดตของฉันโดยที่บรรทัดมีเพียงแท็บหรือช่องว่างเท่านั้นเพื่อระบุว่าเป็น 0
αғsнιη

5
  1. trและเชลล์สคริปต์POSIX :

    tr -d 'N ' < file | while read x ; do echo ${#x} ; done
    
  2. bash, kshและzsh:

    while read x ; do x="${x//[ N]}" ; echo ${#x} ; done < file
    

1
สามารถใช้awk '{print length()}'เพื่อหลีกเลี่ยงเปลือกช้าวนลูป .. แต่แล้วหนึ่งสามารถทำมันทั้งหมดที่มี awk ตัวเอง ...
Sundeep

@Sundeep มันเป็นความจริง ( ถ้าทั้งคู่เริ่มในเวลาเดียวกัน) การawkวนซ้ำนั้นเร็วกว่าการวนรอบเชลล์ แต่เชลล์นั้นอยู่ในหน่วยความจำเสมอและawkอาจจะไม่ - เมื่อawkยังไม่ได้โหลดหรือสับเปลี่ยนโอเวอร์เฮดของการโหลดมัน ( เวลาที่หายไป ) อาจมากกว่าข้อดีของการวิ่งawk- โดยเฉพาะอย่างยิ่งในขนาดเล็ก ห่วง ในกรณีดังกล่าว ( เช่นกรณีนี้) awkอาจจะช้าลง
agc

ดีฉันไม่ต้องกังวลเกี่ยวกับเวลาสำหรับสิ่งเล็ก ๆ ... ดูunix.stackexchange.com/questions/169716/
Sundeep

1
@Sundeep ผมทำกังวล เมื่อก่อนฉันเคยใช้ฟลอปปี้ดิสทริบิวชั่นที่ใช้ฟล็อปปี้ซึ่งสามารถวิ่งออกจากฟลอปปี้ได้ในหน่วยความจำไม่กี่เมกะไบต์ การใช้awkเชลล์สคริปต์โดยไม่จำเป็นอาจทำให้ระบบรวบรวมข้อมูลทั้งสี่ โดยทั่วไป: การลากเวลาแฝงเดียวกันใช้กับระบบในเฟิร์มแวร์ที่ จำกัด หรือระบบใด ๆ ที่มีภาระมาก
agc

1

ชุดสั้น ๆ ของtrและawk:

$ tr -d ' N' <file.in | awk '{ print length }'
1
1
1
0
1
2
2

การทำเช่นนี้จะเป็นการเว้นช่องว่าง Ns ทั้งหมดจากไฟล์อินพุตและawkเพียงพิมพ์ความยาวของแต่ละบรรทัด


0

อีกวิธีที่ง่ายคือทำใน python ซึ่งติดตั้งมาล่วงหน้าในสภาพแวดล้อมของยูนิกซ์ส่วนใหญ่ วางรหัสต่อไปนี้ในไฟล์. py:

with open('geno') as f:
    for line in f:
        count = 0
        for word in line.split():
            if word != 'N':
                count += 1
        print(count)

แล้วทำ:

python file.py

จากสถานีของคุณ สิ่งที่ทำข้างต้นคือ:

  • สำหรับแต่ละบรรทัดในไฟล์ชื่อ "geno"
  • ตั้งค่าตัวนับเป็น 0 และเพิ่มขึ้นทุกครั้งที่เราหาค่า! = 'N'
  • เมื่อถึงจุดสิ้นสุดของบรรทัดปัจจุบันให้พิมพ์ตัวนับและไปที่บรรทัดถัดไป
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.