2012-03-24 19 views
5

Biorąc pod uwagę plik w formacie UTF-8, zawierający znaki w różnych językach, w jaki sposób mogę uzyskać liczbę unikalnych znaków, które zawiera, z wyłączeniem wybranej liczby symboli (np. "!", "@", " # ",". ") z tej liczby?Jak policzyć liczbę unikalnych znaków w pliku?

+1

nie można zrobić tylko bash. Musisz napisać pełny program w bashu. W takim przypadku lepiej używać języka programowania. –

+1

Czy istnieje jakiś szczególny powód, dla którego musisz użyć "bash"? – paulsm4

+0

Brzmi jak praca domowa ... – fbernardo

Odpowiedz

2

Korzystanie z Perl jedno-liner:

echo -e "aba\ncfg!ഡ.#g" | perl -C7 -ne 'for(split(//)){if ($_ !~ /[[email protected]#.]/) { print $_."\n"}}' | sort | uniq | wc -l 

WYJŚCIE7

Jeśli chcesz ignorować przełamane:

echo -e "aba\ncfg!ഡ.#g" | perl -C7 -ne 'for(split(//)){if ($_ !~ /[[email protected]#.\n]/) { print $_."\n"}}' | sort | uniq | wc -l 

WYJŚCIE6

+1

Jedna linijka w perlu + bash masz na myśli? –

+1

@gnibbler Powiedziałem ** używając ** jednego liniowca. Masz rację, to była misfrase - napisałem, że jedna rzecz znaczy inna. Poprawiono to. Dzięki za wskazanie. –

5

W Pythonie:

import itertools, codecs 

predicate = set('[email protected]#.').__contains__ 
unique_char_count = len(set(itertools.ifilterfalse(
         predicate, itertools.chain.from_iterable(codecs.open(filename, encoding="UTF-8"))))) 

Kiedy iteracyjne nad plikiem, można uzyskać linie. chain łączy je razem, więc powtarzając nad nim, otrzymujesz postacie. ifilterfalse eliminuje znaki, które spełniają warunek, z warunkiem zdefiniowanym jako członkostwo w zbiorze niedozwolonych znaków.

Bez itertools:

import codecs 
disallowed = set('[email protected]#.') 
unique_char_count = len(set(char for line in codecs.open(filename, encoding="UTF-8") for char in line 
           if char not in disallowed)) 

Korzystanie zestaw operacji:

import codecs 
unique = set() 
any(unique.update(line) for line in codecs.open(filename, encoding="UTF-8")) 
unique.difference_update('[email protected]#.') 
unique_char_count = len(unique) 
+3

Wydaje mi się, że potrzebujesz łańcucha * lub a.from_iterable, aby łańcuch działał w ten sposób. – DSM

+1

@ DS Dzięki, brakowało '' fromz_ableable'. Dodano również wersję nie-itertools. – agf

+1

Możesz chcieć określić kodowanie z tym wywołaniem "open". –

8

Oto rozwiązanie bash. :)

bash$ perl -CSD -ne 'BEGIN { $s{$_}++ for split //, q([email protected]#.) } 
        $s{$_}++ || $c++ for split //; 
        END { print "$c\n" }' *.utf8 
+0

"Oto rozwiązanie bash" ... NIE! ;) – paulsm4

+0

+1 za policzek ;-) –

+0

tchrist, jaki byłby w scenariuszu odpowiednik '-CSD'? –

2

będę po prostu rzucić w moim języku nie-wymagane opcją na dokładkę:

sed 's/[[email protected]#.]//g' /path/to/file | sed 's/./\0\n/g' | sort -u | wc -l 
+1

To nawet nie przychodzi * nigdzie ** zamknij *** do pracy w moim systemie dla plików UTF-8. Przed 'wc', istnieje garść linii takich jak' 0n0n0n0n', '0n0n0n0n0n0n0n0n', itd. I tak, LANG =' en_US.UTF-8'. Nie używasz standardowego POSIX-a, prawda? – tchrist

+0

@Andrew Kandels - Myślę, że to świetne rozwiązanie. Jeśli oryginalny plik ma 16-bitowy kod Unicode, zawsze możesz użyć iconv: 'iconv -f utf-16 -t ascii plik_źródłowy | sed 's /[[email protected]#.]// g'/path/do/file | sed 's/./ \ 0 \ n/g' | sort -u | wc -l' – paulsm4

+0

Przepraszamy, rozmieszczone w części UTF-8. dodatek @ paulsm4 powinien jednak rozwiązać ten problem. –

1

Wpisz zestawy w Pythonie. powiedzmy chcesz dowiedzieć się unikalne znaki w pliku url.txt

f=open('url.txt') 
a='' 
for x in f: 
    x=x.split(' ') 
    for y in x: 
    a+=y 
unique=set(a)-set('@!#.') #add the characters that you wanna neglect in the second set 
print(unique) 
print('unique characters : ',len(unique)) 

powiedzmy URL.TXT zawiera:

Google --! google.com --! coolest search engine 

facebook --! facebook.com --! biggest social network 

yahoo --! yahoo.com --! biggest web portal 

wyjściowy będzie:

{'a', 'G', 'm', '\n', 'n', 'c', 'b', 'e', 'g', 'f', 'i', 'h', 'k', '-', 'l', 'o', 'p', 's', 'r', 't', 'w', 'y'} 
unique characters : 22 
+0

Moja odpowiedź już zawiera kilka wersji Pythona, które są zasadniczo takie same. Ponadto wydajność twojego konstruktora stringów jest __terrible__. Dodawanie ciągów jest powolne - jeśli musisz usunąć spacje i dołączyć do linii, powinieneś użyć czegoś takiego jak ''' .join (''. Join (x.split()) dla x w f)' które będzie znacznie szybsze . Zobacz moją odpowiedź na sposoby, aby to zrobić bez budowania długich ciągów. – agf

0

jednym alternatywnym:

filename='/somewhere/my-file-in-utf8' 

iconv -f UTF8 -t UTF16 $filename | tail -c +3 | \ 
perl -pi -e "s/\x00\@//g; s/\x00\!//g; s/\x00\#//g; s/\x00\.//g;" | \ 
od | cut -b 8- | xargs -n 1 | sort | uniq | wc -l 
+1

zapomniałem o unikalnej części, post został naprawiony. – pizza

3

rubin, wykorzystujące zestawy:

require 'set' 
string = 'ababbbababbabcdcccdbbaaba' 
ignore = 'c' 
(Set.new(string.chars) - Set.new(ignore.chars)).count 
# => 3 
  • string jest ciąg wejściowy
  • ignore jest ciągiem z postaciami ignorować
  • string.chars znajduje się lista znaków w ciąg
  • Set.new Tworzy zestaw z niego
  • - daje różnicę między dwoma zestawami
  • count jest liczba elementów w wynikowa
+2

'ignore.chars' wystarczy; nie trzeba go konwertować do zestawu. – steenslag

3

Innym rubin pierwszy:

#encoding: utf-8 
string = '@étude#@étude ฒณ!' 
ignore = '[email protected]#.' 
p string.chars.to_a.uniq.join.delete(ignore).size #=>8 
2

Zrobiłem to w python po 3 godzinach badań, ale zrobiłem to

fname = "temp.txt" 
num_lines = 0 
num_words = 0 
num_chars = 0 
num_uniq = 0 
a = [] 
exclude = ",[email protected]#$" 
with open(fname, 'r') as f: 
    for line in f: 
     words = line.split() 
     for word in words: 
       char = list(word) 
       a = a + char 
     num_lines += 1 
     num_words += len(words) 
     num_chars += len(line) 
print "Lines:%s\nWords:%s\nChars:%s" % (num_lines, num_words, num_chars) 
num_uniq = len(set(a)-set(exclude)) 
print "Unique Characters:%d" % (num_uniq) 

tutaj jest wyjście

Lines:6 
Words:74 
Chars:385 
Unique Characters:26 
Powiązane problemy