Autor Wątek: Zliczanie liter.  (Przeczytany 2767 razy)

Offline _user

  • Użytkownik

# Sierpień 21, 2015, 00:38:45
Przepraszam ze tak temat po temacie xd Ale tamten szybko rozwiazany to jakby sie nie liczyl ^^

Wiec chce napisac program ktory: Pobiera tekst, potem liczy ile razy wystapila kazda litera w tekscie i wypisuje je w tabeli w kolejnosci: a - z nastepnie A - Z np:
a = 2
c = 0
z = 5
B = 8
X = 2
i tak dalej i tak dalej, i nie mam pojecia jak to zrobic, jak napisac funkcje ktora zliczy wystapienie dalej litery moze jeszczcze ale wypisze w takiej kolejnosci to juz zupelnie nie wiem,przydalby sie ktos kto wie.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Xion

  • Redaktor
    • xion.log

  • +3
# Sierpień 21, 2015, 01:24:28
from collections import Counter
import string

text = raw_input('Text: ')
counter = Counter(text)
for letter in string.letters:
    print('%s = %s' % (letter, counter[letter])

Offline _user

  • Użytkownik

# Sierpień 21, 2015, 01:45:45
hmmm Niezbyt rozumiem twoj kod Xion, jakies nieznane mi funkcje, one sa w bibliotekach C ? Bo sorki ale znowu zapomnialem dodac ze program ma byc w C.

Offline Xender

  • Użytkownik

  • +1
# Sierpień 21, 2015, 11:02:49
@Xion:
Tutaj masz wersję zupgrade'owaną do 3k-i*
*nie, ten myślnik w tym miejscu to nie typo, to nawiązanie do określenia. Zresztą IIRC takie odmienianie liczb przez myślnik i tak jest nie do końca poprawne gramatycznie :)

from collections import Counter
import string

text = input('Text: ')
counter = Counter(text)
for letter in string.letters:
    print(letter, "=", counter[letter])

I generalnie polecam "{}".format(), chociażby dlatego, że "{nazwany}następne słowo".format(nazwany=1) wygląda o wiele czytelniej od "%(nazwany)snastępne słowo" % {...} (literki będące elementem znacznika formatowania nie zlewają się z dalszym tekstem).

jakies nieznane mi funkcje, one sa w bibliotekach C?

<trochę_wredny>
Jeśli się bardzo uprzesz, to możesz korzystać z CPyhtona jako biblioteki z poziomu C.
Ale nie polecam robić tego, żeby dostać się do kilku funkcji.
</trochę_wredny>

Zacznij od zapoznania się z tym i zdefiniowania pojęcia "litery" tak, żeby miała sens w kontekście Jedynego Słusznego Unicode:
http://www.utf8everywhere.org/#faq.glossary

Przy okazji, jeśli w grę wchodzi C++ zamiast C, to do Unicode polecam tę libkę:
http://utfcpp.sourceforge.net/

Tak, w C++11 do biblioteki standardowej weszły jakieś konwersje Unicode'owe.
Ledwo się im przyglądałem, ale nie używałbym ich.
Interfejs tej małej libki wygląda zdecydowanie przyjaźniej i przewidywalniej, niż kolejnego potworka z biblioteki standardowej C++.

Offline _user

  • Użytkownik

# Sierpień 21, 2015, 11:58:20
no ale ogolnie ten kod jest w c++ tak ? W gre nie wchodzi c++, jak napisalem chce ten program napisac w C, takze jakby ktos wiedzial jak pomoc byloby dobrze : )

Offline Xender

  • Użytkownik

  • +2
# Sierpień 21, 2015, 12:07:15
No ale ogolnie ten kod jest w c++ tak?

Xionowy jest w Pythonie. I składnia Pythona jest naprawdę dość drastycznie różna od składni C++...
UTF8-CPP jest w C++, mocno korzysta z templatek.

A ustaliłeś już (korzystając z linka do FAQ z UTF8 Everywhere), co tak właściwie chcesz zliczać?
Pewnie i tak odpowiesz, że bajty, a nie znaki, bo to pewnie jakieś zadanie domowe...

A jeśli to zadanie domowe, do dostając kod w Pythonie, który musisz już teraz "tylko" przepisać do C, masz już trochę łatwiej.
« Ostatnia zmiana: Sierpień 21, 2015, 12:09:07 wysłana przez Xender »

Offline _user

  • Użytkownik

# Sierpień 21, 2015, 12:11:34
To nie jest zadanie domowe.Jak wgl mozna takie rzeczy wnioskowac... Jesli chodzilbym do szkoly i dostal takie zadanie domowe to bym nie pytal na forum tylko opieprzyl nauczyciela ze mi nie wytlumaczyl.A pythona nie znam wcale, nie wiem jak to przepisac.
« Ostatnia zmiana: Sierpień 21, 2015, 12:23:45 wysłana przez _user »

Offline Karol

  • Użytkownik

# Sierpień 21, 2015, 12:43:11
Zrób sobie tabelkę 0..255, i pętlą po tekście leć bajt po bajcie i dany bajt traktuj jako indeks tablicy i inkrementuj tam wartość o jeden. Na koniec wypisz wszystko z tablicy od indeksu 65 do 90, oraz od 97 do 122 :)

Oczywiście nie będzie to działać poprawnie na kodowaniu innym niż ASCII.

Offline _user

  • Użytkownik

# Sierpień 21, 2015, 12:56:21
Mhm, ale jak "leciec bajt po bajcie " ? ^^

I znalazlem taki kod w internecie:
Kod: (c) [Zaznacz]
#include <stdio.h>
 
int main(void) {
    int tablica[128] = {};
    int znak;
    while((znak=getc(stdin))!=EOF){
        tablica[znak]++;
    }
    for(char znak = 'a'; znak<='z';znak++){
      printf("%c %d\n", znak, tablica[znak]);
    }
    for(char znak = 'A'; znak<='Z';znak++){
      printf("%c %d\n", znak, tablica[znak]);
    }
    return 0;
}

Tylko nie rozumiem dzialania:
1.Moglby mi ktos wyjasnic na jakiej zasadzie ten kod segreguje liczby w kolejnosci alfabetycznej ? Ktore miejsce za to odpowiada, skad program wie w jakiej kolejnosci sa liczby w alfabecie ?
2.Czy ta zmienna char znak to ta sama co int znak ? 
3.Oraz jak zmienic ten program zeby nie wypisywal tych miejsc gdzie jest 0 ? probowalem if i while ale nic nie dalo
« Ostatnia zmiana: Sierpień 21, 2015, 13:29:19 wysłana przez _user »

Offline Xender

  • Użytkownik

  • +2
# Sierpień 21, 2015, 14:37:47
Wczytywać tekst z stdin po bajcie (getchar) albo lepiej (wydajniej) większymi porcjami do tablicy.

To C, więc musisz z góry znać górną granicę długości tekstu, albo wczytywać na raty, a jeśli kodowanie będzie miało zmienną długość (jak UTF-8 czy UTF-16), to jeszcze obsłużyć sytuacje, gdy koniec bufora trafi się w połowie jednego znaku.

Jak już zdecydujesz się na metodę wczytywania i to, czy uwzględniać Unicode, to zrobić sobie tablicę/hashmapę intów (oczywiście wszelkie nietrywialne struktury danych w C to przeważnie cała masa makr) indeksowaną kodem znaku (jeśli interesuje Cię tylko ASCII i tylko litery, to może być i zwykła tablica, może mieć odpowiednio mniej niż 255 elementów, jeśli chce Ci się odejmować najmniejszy kod litery z ASCII przed zaindeksowaniem nim tablicy).

Pamiętaj, żeby tablicę zainicjalizować zerami.

Potem lecisz po wczytanych znakach/bajtach (wołanie getchar() w pętli - wbrew nazwie zwraca bajty, nie znaki. No i jeszcze znacznik EOF, ale to po prostu znacznik oznaczający że strumień jest już pusty, niejako dodawany przez bibliotekę C), indeksujesz kodem znaku tablicę/hashmapę i zwiększasz inta pod wynikową pozycją.

Na końcu iterujesz przez całą tablicę/mapę i wypisujesz znak o kodzie będącym indeksem danej pozycji i wartość - liczbę wystąpień.


Brzmi skomplikowanie?
Tak, to C, gdzie stworzenie w miarę użytecznego i jednocześnie kompletnego programu jest skomplikowane.
Zliczanie bajtów (w C i C++ mylnie nazwanych "char") będzie dużo prostsze niż zliczanie znaków w jakimś sensownym kodowaniu - ale pożegnaj się z ogonkami (ASCII) lub z uniwersalnością względem locale (różne strony kodowe itp. o stałej długości).

Czemu w C++ jest dużo łatwiej, a w Pythonie to już w ogóle?
Bo mają miejscami milsze API od I/O, a ten drugi nawet wbudowaną obsługę Unicode.
Przeważnie po prostu ukrywają większość tej skomplikowanej maszynerii pod maską, a czasem (to rzadziej) robią coś inaczej, z pominięciem mechanizmów z biblioteki C (które zadomowiło się już jako najmniejszy wspólny mianownik dla bardzo wielu języków i bibliotek), bo czasem łatwiej konstruktorom tych języków zaimplementować konkretną rzecz po swojemu.


A nie wiem, jakoś tak zawiało zadaniem domowym, bo mało informacji, po co to potrzebne, ściśle ustalone wytyczne, na których poparcie brak argumentów ("ma być w C") i mało konkretne polecenie ("litery" czyli jaki konkretniej podzbiór znaków z jakiego kodowania?).

Ok, jeśli szukasz sobie zadań sam dla siebie, żeby poćwiczyć C, to jeszcze ma sens.
Jeśli chcesz użyć tego programu w jakimś poważniejszym celu, to okaże się, że nie zlicza ogonków, albo co gorsza się na nich wysypuje, a żeby dorobić sensownie ich obsługę stanie się 10x dłuższy...

Offline _user

  • Użytkownik

# Sierpień 21, 2015, 14:42:29
Tak jak mowisz, sam robie zadania dla siebie zeby cwiczyc C :) A argumentem dlaczego "Ma byc w C" jest to ze chce sie uczyc C a nie C++ czy tez Pythona.Skomplikowane rzeczy chcialbym kiedys umiec robic ale jeszcze sporo praktyki C przede mna jesli wgl to wyjdzie ale co do pytan ktore zadalem wyzej odnosnie tego kodu co wrzucilem:
Kod: (c) [Zaznacz]
#include <stdio.h>
 
int main(void) {
    int tablica[128] = {};
    int znak;
    while((znak=getc(stdin))!=EOF){
        tablica[znak]++;
    }
    for(char znak = 'a'; znak<='z';znak++){
      printf("%c %d\n", znak, tablica[znak]);
    }
    for(char znak = 'A'; znak<='Z';znak++){
      printf("%c %d\n", znak, tablica[znak]);
    }
    return 0;
}

1.Moglby mi ktos wyjasnic na jakiej zasadzie ten kod segreguje liczby w kolejnosci alfabetycznej ? Ktore miejsce za to odpowiada, skad program wie w jakiej kolejnosci sa liczby w alfabecie ?
2.Czy ta zmienna char znak to ta sama co int znak ?
3.Oraz jak zmienic ten program zeby nie wypisywal tych miejsc gdzie jest 0 ? probowalem if i while ale nic nie dalo
« Ostatnia zmiana: Sierpień 21, 2015, 15:37:36 wysłana przez _user »

Offline voytech

  • Użytkownik

# Sierpień 21, 2015, 16:22:37
Kod: (c) [Zaznacz]
    for(char znak = 'a'; znak<='z';znak++){
      printf("%c %d\n", znak, tablica[znak]);
    }
Cytuj
1.Moglby mi ktos wyjasnic na jakiej zasadzie ten kod segreguje liczby w kolejnosci alfabetycznej ? Ktore miejsce za to odpowiada, skad program wie w jakiej kolejnosci sa liczby w alfabecie ?

z kodu ASCII 'a' == 97 i 'z'==122, więc powyższy kod jest równoważny temu:
Kod: (c) [Zaznacz]
    for(char znak = 97; znak<=122;znak++){
      printf("%c %d\n", znak, tablica[znak]);
    }
'a' + 1 == 'b', 'a'+2 == 'c', itd. Stąd wynika ta cała kolejność alfabetyczna, czyli z porządku liczb całkowitych

2.Czy ta zmienna char znak to ta sama co int znak ?
nie, to jest zmienna lokalna pętli for

btw, 'int znak' jest dlatego że getc odczytuje bajt jako 'unsigned char' 0..255, ale rzutuje to na 'int', żeby mieć możliwość poinformowania użytkownika tej funkcji o wystąpieniu końca pliku (EOF==-1). Schemat jest prosty, odczytujesz int z getc i sprawdzasz czy wynosi EOF . Jeżeli nie jest to wartość -1 to znaczy że jest to poprawnie odczytany znak i int można sobie zrzutować na unsigned char albo zwykły char.

3.
Kod: (c) [Zaznacz]
    for(char znak = 'a'; znak<='z';znak++){
       if (tablica[znak] != 0)
           printf("%c %d\n", znak, tablica[znak]);
    }
i podobnie dla wielkich liczb 'A'..'Z'

Offline Xirdus

  • Moderator

  • +4
# Sierpień 22, 2015, 14:32:40
Tak na marginesie - pisanie w czystym C jest o wiele, wiele, wiele trudniejsze od pisania w C++, a sam C++ jest o wiele, wiele, wiele trudniejszy od Pythona ;)

Offline Xender

  • Użytkownik

  • +2
# Sierpień 22, 2015, 17:36:28
Tak na marginesie - pisanie w czystym C jest o wiele, wiele, wiele trudniejsze od pisania w C++, a sam C++ jest o wiele, wiele, wiele trudniejszy od Pythona ;)

A dobrze jest dobrze znać (nie tylko z tych trzech, w ogóle) więcej niż jeden, a o różnych innych mieć przynajmniej jakieś pojęcie.

Jak byłem mniej doświadczony, niż teraz (a nadal jestem w dużej mierze amatorem), to C++ "był moim oczkiem w głowie" i myślałem, że zrobię w nim wszystko, a jego natywna szybkość bije wszystko na głowę (taa~, jaasne...) - tylko jakoś wiele zadań wydawało się bardzo skomplikowanych.

A potem przyszedł linuxowy shell, potem Python i wiele z tych "zbyt skomplikowanych" problemów stało się wykonalne, proste czy trywialne.

Nawet w grach AAA, które [przynajmniej teoretycznie] powinny być optymalizowane, żeby wycisnąć co się da ze sprzętu w użyteczny sposób, używa się skryptów - jakoś się okazuje, że narzut maszyny wirtualnej, JIT-a itp. czy chociażby ABI wymagającego dodatkowych czynności jest akceptowalny.