Dosyadaki her karakterin sayısını saymanın en hızlı yolu nedir?


121

A'nın C'lerinin G'lerinin N'lerini ve bir dosyadaki "-" karakterlerini veya gerektiğinde her harfini saymak istiyorum, bunu yapmak için hızlı bir Unix komutu var mı?


56
DNA ipliklerinde baz sayma?
Indrek,

12
Bu soruyu seviyorum, aynı sorunu çözmek için kullanılan birçok farklı yaklaşım ve araç.
Journeyman Geek

10
Heh, bu sınırda kod-golf
Earlz

13
Birisi windows powershell versiyonu ile ilgileniyorsa:[System.IO.File]::ReadAllText("C:\yourfile.txt").ToCharArray() | Group-Object $_ | Sort Count -Descending
Guillaume86

4
Tamam, saf PS yolunu bulduğumu düşünüyorum:Get-Content "C:\eula.3082.txt" | % { $_.ToCharArray() } | Group-Object | Sort Count -Descending
Guillaume86

Yanıtlar:


136

Bazı gerçek hız istiyorsanız:

echo 'int cache[256],x,y;char buf[4096],letters[]="tacgn-"; int main(){while((x=read(0,buf,sizeof buf))>0)for(y=0;y<x;y++)cache[(unsigned char)buf[y]]++;for(x=0;x<sizeof letters-1;x++)printf("%c: %d\n",letters[x],cache[letters[x]]);}' | gcc -w -xc -; ./a.out < file; rm a.out;

İnanılmaz derecede hızlı bir sözde tek astar.

Basit bir test Core i7 CPU 870 @ 2.93GHz’de 600 MB / sn’den fazla olduğunu gösteriyor:

$ du -h bigdna 
1.1G    bigdna

time ./a.out < bigdna 
t: 178977308
a: 178958411
c: 178958823
g: 178947772
n: 178959673
-: 178939837

real    0m1.718s
user    0m1.539s
sys     0m0.171s

Sıralama içeren çözümlerden farklı olarak, bu, dosyanız raminizden çok daha büyükse, çok yararlı olan sabit (4K) bellekte çalışır.

Ve elbette, biraz dirsek yağıyla, 0.7 saniye tıraş oluruz:

echo 'int cache[256],x,buf[4096],*bp,*ep;char letters[]="tacgn-"; int main(){while((ep=buf+(read(0,buf,sizeof buf)/sizeof(int)))>buf)for(bp=buf;bp<ep;bp++){cache[(*bp)&0xff]++;cache[(*bp>>8)&0xff]++;cache[(*bp>>16)&0xff]++;cache[(*bp>>24)&0xff]++;}for(x=0;x<sizeof letters-1;x++)printf("%c: %d\n",letters[x],cache[letters[x]]);}' | gcc -O2 -xc -; ./a.out < file; rm a.out;

1.1GB / sn'nin üzerindeki ağlar:

real    0m0.943s
user    0m0.798s
sys     0m0.134s

Karşılaştırma için, bu sayfadaki bir tür hız sözü vermiş gibi görünen diğer çözümlerden bazılarını test ettim.

sed/ awkÇözüm yiğit çaba, ancak 30 saniye sonra öldü. Böyle basit bir regex ile, bunun sed'de bir hata olmasını bekliyorum (GNU sed sürüm 4.2.1):

$ time sed 's/./&\n/g' bigdna | awk '!/^$/{a[$0]++}END{for (i in a)print i,a[i];}' 
sed: couldn't re-allocate memory

real    0m31.326s
user    0m21.696s
sys     0m2.111s

Perl yöntemi de umut verici görünüyordu, ancak 7 dakika çalıştırdıktan sonra pes ettim

time perl -e 'while (<>) {$c{$&}++ while /./g} print "$c{$_} $_\n" for keys %c' < bigdna 
^C

real    7m44.161s
user    4m53.941s
sys     2m35.593s

1
+1 Çok fazla veri olduğunda mantıklı bir çözüm için, sadece bir avuç bayt değil. Dosyalar disk önbelleğinde olsa da değil mi?
Daniel Beck

2
İşin güzel yanı, işlemede O (N) ve bellekte O (1) karmaşıklığı olması. Borular genellikle işleme sırasında O (N log N) (ya da hatta O (N ^ 2)) ve O (N) bellekte bulunur.
Martin Ueding,

73
Yine de, "komut satırı" tanımını oldukça zorluyorsunuz.
gerrit

11
Sorunun gereksinimlerinin epik bükülmesi -I onaylıyorum, s. superuser.com/a/486037/10165 <- Birisi kriterler koştu ve bu olduğunu en hızlı seçenek.
Journeyman Geek

2
+1 C'yi doğru yerlerde iyi kullandığım için teşekkür ederim.
Jeff Ferland

119

grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c

Hile bir liner olarak yapacağız. Yine de küçük bir açıklamaya ihtiyaç var.

grep -o foo.text -e A -e T -e C -e G -e N -e -a ve g harfleri için foo.text dosyasını ve -aramak istediğiniz her karakterin karakterini gösterir. Aynı zamanda bir karakteri bir satır yazdırır.

sortsırayla sıralar. Bu, bir sonraki takım için sahneyi belirler

uniq -cHerhangi bir satırın art arda yinelenen oluşumlarını sayar. Bu durumda, sıralanmış bir karakter listesine sahip olduğumuz için, ilk adımda çizdiğimiz karakterleri ne zaman temiz bir şekilde alıyoruz?

Foo.txt dizgiyi içeriyorsa, GATTACA-bu komutlardan elde edeceğim şey budur

[geek@atremis ~]$ grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c
      1 -
      3 A
      1 C
      1 G
      2 T

8
Kanlı tek kelimeyle sihir! : D
Pitto

27
eğer dosyalarınızda sadece CTAG karakterleri varsa, regexp'in kendisi anlamsız hale gelir, değil mi? grep -o. | sıralama | uniq -c eşit derecede iyi çalışır, afaik.
sylvainulg

7
+1 25 yıldır grep kullanıyorum ve bilmiyordum -o.
LarsH

9
@JourneymanGeek: Bununla ilgili sorun, sıralama için iletilen çok fazla veri üretmesidir. Bir programın her karakteri ayrıştırabilmesi daha ucuz olurdu. Dave'in bir O (1) cevabı yerine O (N) bellek karmaşıklığı cevabı bölümüne bakınız.
Martin Ueding,

2
@Pitto Native Windows coreutils sürümleri yaygın olarak bulunmaktadır - Google’a veya bir başkasına sormanız yeterli
OrangeDog

46

@ Journeyman'ın cevabından ilham alan bunu deneyin.

grep -o -E 'A|T|C|G|N|-' foo.txt | sort | uniq -c

Anahtar grep için -o seçeneğini bilmektir . Bu, eşleşmeyi böler, böylece her bir çıktı çizgisi, eşleşen herhangi bir çizginin tamamı yerine, tek bir model örneğine karşılık gelir. Bu bilgi ışığında, ihtiyacımız olan tek şey kullanmak için bir kalıp ve satırları saymanın bir yoludur. Bir regex kullanarak, bahsettiğiniz karakterlerden herhangi biriyle eşleşecek ayrık bir düzen oluşturabiliriz:

A|T|C|G|N|-

Bu, "A veya T veya C veya G veya N veya -" ile eşleşmesi anlamına gelir. El kitabı, kullanabileceğiniz çeşitli düzenli ifade sözdizimini açıklar .

Şimdi buna benzeyen bir çıktımız var:

$ grep -o -E 'A|T|C|G|N|-' foo.txt 
A
T
C
G
N
-
-
A
A
N
N
N

Son adımımız sort | uniq -c@ Journeyman'ın cevabında olduğu gibi , basitçe gerçekleştirilebilecek tüm benzer çizgileri birleştirmek ve saymak . Sıralama bize şu şekilde çıktı veriyor:

$ grep -o -E 'A|T|C|G|N|-' foo.txt | sort
-
-
A
A
A
C
G
N
N
N
N
T

Bu, içinden geçtiğinde uniq -cnihayet istediklerimize benziyor:

$ grep -o -E 'A|T|C|G|N|-' foo.txt | sort | uniq -c
      2 -
      3 A
      1 C
      1 G
      4 N
      1 T

Ek: Bir dosyadaki A, C, G, N, T ve - karakterlerinin toplamını almak istiyorsanız, grep çıktısını wc -lbunun yerine yönlendirebilirsiniz sort | uniq -c. Bu yaklaşımda sadece küçük değişikliklerle güvenebileceğiniz birçok şey var.


Gerçekten coreutils ve regex olan tavşan deliklerine bakmam gerekiyor. Bu benim için biraz daha zarif; p
Journeyman Geek

2
@JourneymanGeek: Regex'i kaybetmek belaya değmez, çünkü pek çok şey için faydalıdır. Sadece sınırlarını anlayın ve XHTML'yi ayrıştırmaya çalışmak gibi, regexes yeteneklerinin dışında bir şeyler yapmaya çalışarak gücü kötüye kullanmayın .
crazy2be

20
grep -o '[ATCGN-]' burada biraz daha okunabilir olabilir.
sylvainulg

14

Python kullanarak tüm harfleri sayan bir liner:

$ python -c "import collections, pprint; pprint.pprint(dict(collections.Counter(open('FILENAME_HERE', 'r').read())))"

... şöyle bir YAML dostu çıktı üretmek:

{'\n': 202,
 ' ': 2153,
 '!': 4,
 '"': 62,
 '#': 12,
 '%': 9,
 "'": 10,
 '(': 84,
 ')': 84,
 '*': 1,
 ',': 39,
 '-': 5,
 '.': 121,
 '/': 12,
 '0': 5,
 '1': 7,
 '2': 1,
 '3': 1,
 ':': 65,
 ';': 3,
 '<': 1,
 '=': 41,
 '>': 12,
 '@': 6,
 'A': 3,
 'B': 2,
 'C': 1,
 'D': 3,
 'E': 25}

Python'un çoğu zaman kod netliği açısından bash'ı bile nasıl kolayca yenebildiğini görmek ilginçtir.


11

Guru'nun awkmetoduna benzer :

perl -e 'while (<>) {$c{$&}++ while /./g} print "$c{$_} $_\n" for keys %c'

10

UNIX'i birkaç yıl kullandıktan sonra, çeşitli filtreleme ve sayma görevlerini gerçekleştirmek için birkaç küçük işlemi birbirine bağlama konusunda çok ustalaşırsınız. Herkes bazıları gibi kendi style-- sahiptir awkve sedbazı benzeri cutve tr. İşte yapacağım yol:

Belirli bir dosya adını işlemek için:

 od -a FILENAME_HERE | cut -b 9- | tr " " \\n | egrep -v "^$" | sort | uniq -c

veya filtre olarak:

 od -a | cut -b 9- | tr " " \\n | egrep -v "^$" | sort | uniq -c

Bu gibi çalışır:

  1. od -a dosyayı ASCII karakterlerine ayırır.
  2. cut -b 9-önek odkoyar ortadan kaldırır .
  3. tr " " \\n Karakterler arasındaki boşlukları yeni satırlara dönüştürür, böylece satır başına bir karakter vardır.
  4. egrep -v "^$" Bunun yarattığı tüm boş satırlardan kurtulur.
  5. sort her karakterin örneğini birlikte toplar.
  6. uniq -c Her satırın tekrar sayısını sayar.

"Merhaba dünya!" Diye besledim. ardından bir newline takip etti ve şunu aldım:

  1 ,
  1 !
  1 d
  1 e
  1 H
  3 l
  1 nl
  2 o
  1 r
  1 sp
  1 w

9

sedBölüm dayalı olan @ Guru'nun cevap , burada kullanarak başka yaklaşım uniqDavid Schwartz'ın' çözeltisine benzer.

$ cat foo
aix
linux
bsd
foo
$ sed 's/\(.\)/\1\n/g' foo | sort | uniq -c
4 
1 a
1 b
1 d
1 f
2 i
1 l
1 n
2 o
1 s
1 u
2 x

1
Kullanım [[:alpha:]]yerine .de sedtek maç karakterler ve değil yeni satırların için.
Claudius,

1
[[:alpha:]]ayrıca -, soruda belirtilen gibi eşleşmeye de çalışıyorsanız başarısız olur
Izkata

Doğru. İlk herşeyi filtrelemek için sed ve sonra açıkça istenen karakterler maç için ikinci bir ifade eklemek için güzel olabilir: sed -e 's/[^ATCGN-]//g' -e 's/\([ATCGN-]\)/\1\n/g' foo | sort | uniq -c. Ancak, oradaki yeni hatlardan nasıl kurtulacağımı bilmiyorum: \
Claudius

7

Bunu birleştirebilir grepve wcbunu yapabilirsiniz:

grep -o 'character' file.txt | wc -w

grepbelirtilen metni belirtilen dosyalarda arar ve -oseçenek, arama metninin bulunduğu her satırı yazacak varsayılanın yerine, yalnızca gerçek eşleşmeleri (yani aradığınız karakterleri) yazdırmasını söyler. bulundu.

wcHer dosya için bayt, sözcük ve satır sayıları veya bu durumda grepkomutun çıktısını yazdırır . -wSeçenek her kelime arama karakterinin bir olay olmanın, kelimeleri saymak söyler. Tabii ki, -lseçenek (satırları sayan) de işe yarar, çünkü greparama karakterinizin her bir oluşumunu ayrı bir satıra yazdırır.

Bunu bir kerede birkaç karakter yapmak için, karakterleri bir diziye yerleştirin ve üzerine yerleştirin:

chars=(A T C G N -)
for c in "${chars[@]}"; do echo -n $c ' ' && grep -o $c file.txt | wc -w; done

Örnek: dizeyi içeren bir dosya TGC-GTCCNATGCGNNTCACANN-için çıktı şöyle olacaktır:

A  3
T  4
C  6
G  4
N  5
-  2

Daha fazla bilgi için, bkz. man grepVe man wc.


Bu yaklaşımın dezavantajı, kullanıcı Journeyman Geek'in bir yorumda aşağıda belirttiği gibi, grepher karakter için bir kez çalıştırılması gerektiğidir. Dosyalarınızın büyüklüğüne bağlı olarak, bu fark edilir bir performansa neden olabilir. Diğer taraftan, bu şekilde yapıldığında, hangi karakterlerin arandığını hızlı bir şekilde görmek ve kodun geri kalanından ayrı bir satırda olduklarından bunları eklemek / kaldırmak için biraz daha kolaydır.


3
İstedikleri her karakter için bunu tekrarlamaları gerekecekti ... Ekleyeceğim. Daha zarif bir çözüm olduğuna yemin edebilirim ama daha fazla dürtmeye ihtiyacı var; p
Journeyman Geek

@JourneymanGeek İyi nokta. Akla yayılan bir yaklaşım, karakterleri bir diziye koymak ve onun içinde dolaşmaktır. Gönderimi güncelledim.
Indrek,

çok karmaşık IMO. Sadece grep -e -et ve benzerini kullanın. Bir diziye koyarsanız ve onun içinden geçirirseniz, grep döngüsünü karakter başına bir kez çalıştırmanız gerekmez mi?
Journeyman Geek

@JourneymanGeek Muhtemelen haklısın. uniq -cayrıca güzel formatlanmış çıktılar almanın daha iyi bir yolu gibi görünüyor. Ben * nix gurusu değilim, yukarıda sadece sınırlı bilgimden ve bazı sayfalarımdan bir araya getirmeyi başardım :)
Indrek

Öyleyse ben; p, ve son dönemdeki ödevlerimden biri yaklaşık 5000 adres defteri girişini sıralamayı içeriyordu ve uniq bunu LOT'u kolaylaştırdı.
Journeyman Geek

7

22hgp10a.txt dizisi satırlarını kullanarak sistemimdeki grep ve awk arasındaki zamanlama farkı awk'ın yolunu buluyor ...

[Edit]: Dave'in derlenmiş çözümünü gördükten sonra, tam olarak büyük sayıma duyarlı sayma için bu dosyada ~ 0.1 saniye içinde tamamlandığı için de awk'i unutun.

# A nice large sample file.
wget http://gutenberg.readingroo.ms/etext02/22hgp10a.txt

# Omit the regular text up to the start `>chr22` indicator.
sed -ie '1,/^>chr22/d' 22hgp10a.txt

sudo test # Just get sudo setup to not ask for password...

# ghostdog74 answered a question <linked below> about character frequency which
# gave me all case sensitive [ACGNTacgnt] counts in ~10 seconds.
sudo chrt -f 99 /usr/bin/time -f "%E elapsed, %c context switches" \
awk -vFS="" '{for(i=1;i<=NF;i++)w[$i]++}END{for(i in w) print i,w[i]}' 22hgp10a.txt

# The grep version given by Journeyman Geek took a whopping 3:41.47 minutes
# and yielded the case sensitive [ACGNT] counts.
sudo chrt -f 99 /usr/bin/time -f "%E elapsed, %c context switches" \
grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c

Ghostdog'un büyük / küçük harfe duyarsız sürümü ~ 14 saniye içinde tamamlandı.

Sed, bu sorunun kabul edilmiş cevabında açıklanmıştır .
Kıyaslama, bu sorunun kabul edilmiş cevabı gibidir .
Ghostdog74 tarafından kabul edilen cevap bu soruydu .


1
s/cache[letters[x]]/cache[letters[x]]+cache[toupper(letters[x])]Hızını etkilemeden büyük / küçük harfe duyarsız hale getirmek için benim olabilir .
Dave,

6

Bence herhangi bir makul uygulama sıralamadan kaçınır. Ancak her şeyi 4 kez okumak da kötü bir fikir olduğu için, birinin bir şekilde 4 filtreden geçen, her bir karakter için bir tanesi filtrelenen ve akış uzunluklarının da bir şekilde hesaplandığı bir akım üretebileceğini düşünüyorum.

time cat /dev/random | tr -d -C 'AGCTN\-' | head -c16M >dna.txt
real    0m5.797s
user    0m6.816s
sys     0m1.371s

$ time tr -d -C 'AGCTN\-' <dna.txt | tee >(wc -c >tmp0.txt) | tr -d 'A' | 
tee >(wc -c >tmp1.txt) | tr -d 'G' | tee >(wc -c >tmp2.txt) | tr -d 'C' | 
tee >(wc -c >tmp3.txt) | tr -d 'T' | tee >(wc -c >tmp4.txt) | tr -d 'N' | 
tee >(wc -c >tmp5.txt) | tr -d '\-' | wc -c >tmp6.txt && cat tmp[0-6].txt

real    0m0.742s
user    0m0.883s
sys     0m0.866s

16777216
13983005
11184107
8387205
5591177
2795114
0

Kümülatif toplamlar daha sonra tmp [0-6] .txt.

Bu yaklaşımda yalnızca 1 Mb belleğe daha az dönüştüren 13 boru var.
Tabii ki en sevdiğim çözüm:

time cat >f.c && gcc -O6 f.c && ./a.out
# then type your favourite c-program
real    0m42.130s

Bu çok hoş bir kullanım tr.
adavid

4

Ne hakkında uniqne olduğunu bilmiyordum grep -o, ama @JourneymanGeek ve @ crazy2be hakkındaki yorumlarımın destek almasından dolayı, belki de bunu bir cevaplayıcıya dönüştürmeliyim:

Dosyanızda yalnızca "iyi" karakterler (saymak istediğinizler) olduğunu biliyorsanız,

grep . -o YourFile | sort | uniq -c

Sadece bazı karakterlerin sayılması gerekiyorsa, diğerleri ise (örneğin, ayırıcılar)

grep '[ACTGN-]' YourFile | sort | uniq -c

İlki ., herhangi bir tek karakterle eşleşen normal ifade joker karakterini kullanır . İkincisi, -en son gelmesi dışında, belirli bir sıraya sahip olmayan bir 'kabul edilmiş karakter kümesi' kullanır ( ve A-Carasında herhangi bir karakter 'olarak yorumlanır ). Bu durumda alıntılar gerekir, böylece kabuğunuz varsa tek karakterli dosyaları kontrol etmek için genişletmeyi denemez (ve eğer yoksa "eşleşme yok" hatası üretir).AC

"Sırala" nın ayrıca bir kere -uişaretlemesine dikkat edin, böylece sadece bir kez raporlar, ancak kopyaları saymak için eşlik eden bayrak yoktur, bu nedenle uniqzorunludur.


-ters eğik çizgiyle kaçarsanız en son gelmek zorunda kalmazsınız: '[A\-CTGN]'iyi çalışması gerekir.
Indrek

2

Aptal bir tane:

tr -cd ATCGN- | iconv -f ascii -t ucs2 | tr '\0' '\n' | sort | uniq -c
  • trsilmek ( -d) tüm karakterleri silmek için ( -c) ATCGN-
  • iconv Her bayttan sonra 0 bayt eklemek için ucs2'ye (UTF16 2 baytla sınırlıdır) dönüştürülür,
  • Başka trNL için bu boş karakteri çevirmek. Şimdi her karakter kendi çizgisinde
  • sort | uniq -cHer saymak uniq hattını

Bu standart olmayan (GNU) -ogrep seçeneğine bir alternatif .


Buradaki komutlar ve mantık hakkında kısa bir açıklama verebilir misiniz?
Andrew Lambert,

2
time $( { tr -cd ACGTD- < dna.txt | dd | tr -d A | dd | tr -d C | dd | tr -d G |
dd | tr -d T | dd | tr -d D | dd | tr -d - | dd >/dev/null; } 2>tmp ) &&
grep byte < tmp | sort -r -g | awk '{ if ((s-$0)>=0) { print s-$0} s=$0 }'

Çıkış formatı en iyi değil ...

real    0m0.176s
user    0m0.200s
sys     0m0.160s
2069046
2070218
2061086
2057418
2070062
2052266

Operasyon teorisi:

  • $ ({command | command} 2> tmp) , akışın stderrini geçici bir dosyaya yönlendirir.
  • dd stdin'i stdout'a çıkarır ve stderr'ye iletilen bayt sayısını çıkarır
  • tr -d her seferinde bir karakteri filtreler
  • grep ve sort, gg çıkışını iniş sırasına göre filtreler.
  • awk farkı hesaplar
  • sort, yalnızca işlem sonrası aşamada, dd örneklerinin çıkış sırasındaki belirsizliği gidermek için kullanılır

Hız 60 MBps + gibi görünüyor


İyileştirmeler: tmp'den kurtulmak? ilgili mektubu yazdırmak için 'yapıştır' kullanın?
Aki Suihkonen

1

Örnek dosya:

$ cat file
aix
unix
linux

Komut:

$ sed 's/./&\n/g' file | awk '!/^$/{a[$0]++}END{for (i in a)print i,a[i];}'
u 2
i 3
x 3
l 1
n 2
a 1

Açıklık eksikliği ve açıklama olmadan tek bir astar atmak için -1. AFAIK, bu bir çatal bomba olabilir
PPC

1

Birkaç diğerini birleştirmek

chars='abcdefghijklmnopqrstuvwxyz-'
grep -o -i "[$chars]" foo|sort | uniq -c

| sort -nrSonuçları sıklık sırasına göre ekleyin .


1

Kısa cevap:

Koşullar uygunsa, ofset elde etmek ve sadece bayt saymak için düşük karakter kümelerinin dosya boyutlarını karakter içermeyen bir karakterle karşılaştırın.

Ah, ama karışık detaylar:

Bunların hepsi Ascii karakterleri. Başına bir bayt. Tabii ki dosyalar, işletim sistemi ve onu oluşturan uygulama tarafından kullanılan çeşitli şeyler için hazırlanmış ekstra meta verilere sahiptir. Çoğu durumda, bunların meta verilerden bağımsız olarak aynı miktarda yer kaplamasını beklerdim, ancak ilk önce yaklaşımı test ederken aynı koşulları sürdürmeye çalışacağım ve daha sonra endişelenmeden önce sürekli bir kaygınızın olduğunu doğrulayacağım. Diğer bir sonuç ise, satır kesmelerinin tipik olarak iki ascii beyaz boşluk karakteri içermesi ve sekmelerin veya boşlukların her birinin bir olması. Bunların olacağından emin olabilirseniz ve kaç tanesini önceden bilmenin bir yolu olmazsa, şimdi okumayı bırakırdım.

Çok fazla kısıtlama gibi görünebilir, ancak bunları kolayca kurabilirseniz, bunlara bakacak bir tonunuz varsa (bu DNA'sı muhtemel görünüyor) en kolay / en iyi performans yaklaşımı olarak beni vurgular. Tonlarca dosya uzunluğu denetlemek ve bir sabiti çıkarmak, her birinde grep (veya benzeri) çalıştırmaktan daha hızlı olacaktır.

Eğer:

  • Bunlar, saf metin dosyalarındaki basit, basit dizelerdir
  • Scite (aynı zamanda boşlukları / dönüşleri kontrol ettiğiniz sürece yapıştırma işlemi tamamdır) ya da birisinin yazdığı bazı temel programlar gibi aynı vanilya tarafından biçimlendirilmemiş metin editörü tarafından yaratılan özdeş dosya tiplerindedirler.

Ve Önemli Olmayacak İki Şey Ama İlk İle Test Edeceğim

  • Dosya adları eşit uzunlukta
  • Dosyalar aynı dizinde

Aşağıdakileri yaparak ofset bulmayı deneyin:

Boş bir dosyayı, birkaç insan karakteriyle kolayca okunabilecek karakterlerle birkaç karakterle karşılaştırın. Boş dosyayı diğer iki dosyadan çıkarmak, karakter sayımı ile eşleşen bayt sayıları verirse işiniz biter. Dosya uzunluklarını kontrol edin ve bu boş miktarı çıkarın. Çok satırlı dosyaları bulmayı denemek istiyorsanız, çoğu editör Microsoft tarafından göz ardı edilme eğiliminde olduğundan, satır sonları için iki özel tek baytlık karakter ekler, ancak bu durumda en azından beyaz boşluk karakterlerini izlemeniz gerekir hepsini grep ile yapabilirsiniz.


1

Haskell yolu:

import Data.Ord
import Data.List
import Control.Arrow

main :: IO ()
main = interact $
  show . sortBy (comparing fst) . map (length &&& head) . group . sort

bu gibi çalışır:

112123123412345
=> sort
111112222333445
=> group
11111 2222 333 44 5
=> map (length &&& head)
(5 '1') (4 '2') (3 '3') (2 '4') (1,'5')
=> sortBy (comparing fst)
(1 '5') (2 '4') (3 '3') (4 '2') (5 '1')
=> one can add some pretty-printing here
...

derleme ve kullanma:

$ ghc -O2 q.hs
[1 of 1] Compiling Main             ( q.hs, q.o )
Linking q ...
$ echo 112123123412345 | ./q
[(1,'\n'),(1,'5'),(2,'4'),(3,'3'),(4,'2'),(5,'1')]%       
$ cat path/to/file | ./q
...

belki büyük dosyalar için iyi değil.


1

Hızlı perl hack:

perl -nle 'while(/[ATCGN]/g){$a{$&}+=1};END{for(keys(%a)){print "$_:$a{$_}"}}'
  • -n: Giriş satırlarını yineleyin ancak onlar için hiçbir şey yazdırmayın
  • -l: Satır sonlarını otomatik olarak soyun veya ekleyin
  • while: İstediğiniz sembollerin tüm oluşumlarını geçerli satırda yineleyin
  • END: Sonunda sonuçları yazdır
  • %a: Değerlerin saklandığı karma

Hiç oluşmayan karakterler sonuca dahil edilmeyecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.