Pokaż wyniki 1 do 8 z 8

Temat: [perl] tab. asocjacyjna z pliku? -> musze zrobić logowanie

  1. #1
    Zarejestrowany
    Oct 2008
    Postów
    5

    Question [perl] tab. asocjacyjna z pliku? -> musze zrobić logowanie

    Hej, na wstępie chce nadmienić, że jesteście chyba jednym niewymarłym forum, zatem liczę że otrzymam tutaj jakąś odpowiedź na mój problem, bo z perlem bawię się od tygodnia :P (wcześniej zapoznałem sie z podstawami C, C++, C#, php...)

    No ale do rzeczy.. na zadanie mam napisać skrypt, którego częścią bedzie
    wprowadzenie prostego mechanizmu rejestracji użytkownika (w formie nicka), informacja o graczach powinna być przechowywana w tablicy asocjacyjnej w postaci nick=>liczba_punktow,
    kombinuję z czyms takim:

    Kod:
    open(PLIK, 'C:/quiz_konta.txt') or die "Nie mozna otworzyc pliku: $!"; #dane w pliku: idek,123,user,haslo,123,pass123
    my $linia = <PLIK>;
    my @tablica = $linia;
    %users = @tablica;
    close PLIK;
    jednak chyba nie w tym kierunku droga, bo do pierwszej komórki tablicy zapisywany jest cały plik. A zatem, czy macie pomysł, jak pobrać dane z pliku, aby stworzyć z nich tablice asocjacyjną?

    Lub może macie inny pomysł na rozwiązanie logowania...?

    __________________________________________________
    siedze i kombinuje coś jeszcze z push'em ... ale nie mogę nowej tablicy (@) przenieść na asocjacyjną % kod mniej więcej taki:

    Kod:
    open(PLIK, 'C:/quiz_konta.txt') or die "Nie mozna otworzyc pliku: $!";
    my @linia = <PLIK>;
    my $ograniczenie = @linia;
    my @tablica;
    my %users;
    			do 
    			{
    				for ($i=0; $i<=$ograniczenie; $i++)
    				{
    					push (@tablica, $linia[$i])
    				}
    			}
    			until @linia;
    			%users = @tablica;
    			print %users;
    Ostatnio edytowane przez idek : 10-26-2008 - 00:31

  2. #2
    Zarejestrowany
    Sep 2008
    Postów
    6

    Domyślnie

    Nie wiem czy dobrze zrozumiałem problem, tutaj jest przykładowe tzw. "na szybko" rozwiązania zakładając, że plik ma format następujący:
    Kod:
    username = points
    Poniżej masz kod źródłowy:
    Kod:
    my %quiz = (); 
    
    open(HANDLE, "test.txt");
    while (<HANDLE>) { 
      my @tmp = split(/=/, $_); 
      if (scalar @tmp == 2) {
        if (not defined $quiz{$tmp[0]}) { 
          $quiz{$tmp[0]} = $tmp[1]; 
        } else { 
            $quiz{$tmp[0]} += $tmp[1];
        }   
      }
    }
    close HANDLE;
    W niektórych miejscach potrzebny jest trim oraz chomp oraz przydałoby się sprawdzanie czy podane wartości w pliku są wartościami pożądanymi (wygodnie tutaj będzie skorzystać z wyrażeń regularnych). Rezultatem powyższego kodu będzie zapełnienie tablicy asocjacyjnej wartościami wg. schematu:
    Kod:
    $quiz{"username"} = $points
    Swoją drogą patrząc na Twój kod skorzystałbym z google wykorzystując frazę: perl basics.

  3. #3
    Zarejestrowany
    Oct 2008
    Postów
    5

    Domyślnie

    Hej Marcin, dziękuje za odpowiedź! Zmieniłem nazwy zmiennych z Twojego kodu, aby był bardziej czytelny i wszystko śmiga, naprawdę wielkie dzięki! Poczytalem nieco na temat użytych przez Ciebie wyrażeń, i w sumie początek kodu rozumiem, do momentu
    Kod:
    if (not defined $quiz{$tmp[0]}) { 
          $quiz{$tmp[0]} = $tmp[1]; 
        } else { 
            $quiz{$tmp[0]} += $tmp[1];
        }
    mógłbyś mniej więcej wytłumaczyć, co tutaj sie dzieje domyślam się, że zapisuje zmienne do tablicy asocjacyjnej..? Nie umiem nic znaleźć o "not defined" i w sumie to chyba przez to..

    ale naprawdę wielkie dzięki za konkretną odpowiedź! Aha.. a plik musi mieć postać taką: username=points (bez spacji pomiędzy = )

    a tak btw. masz jakiś pomysł, jak póxniej zapisać nowe punkty do pliku, aby nie naruszyc jego struktury.. czy da się zaktualizowac tylko wiersz, gdzie występuje dany nick, czy trzebabędzie nadpisac cały plik?
    Ostatnio edytowane przez idek : 10-26-2008 - 12:45

  4. #4
    Zarejestrowany
    Sep 2008
    Postów
    6

    Domyślnie

    mógłbyś mniej więcej wytłumaczyć, co tutaj sie dzieje domyślam się, że zapisuje zmienne do tablicy asocjacyjnej..? Nie umiem nic znaleźć o "not defined" i w sumie to chyba przez to..
    Wyrażenie "not defined" jest identycznym do wyrażenia negacji !defined, a o samej konstrukcji defined możesz dowiedzieć się więcej stąd: http://perldoc.perl.org/functions/defined.html
    Kod:
    if (not defined $quiz{$tmp[0]}) { 
          $quiz{$tmp[0]} = $tmp[1]; 
        } else { 
            $quiz{$tmp[0]} += $tmp[1];
        }
    W wolnym tłumaczeniu jeśli nie jest zdefiniowany klucz w tablicy asocjacyjnej o nazwie znajdującej się w pierwszym indeksie tablicy @tmp, to stwórz taki klucz oraz przypisz mu wartość znajdującą się w drugim indeksie tablicy @tmp. W innym przypadku (tj. kiedy klucz istnieje), dodaj wartość znajdującą się pod drugim indeksu tablicy @tmp do wartości znajdującej się pod wskazanym kluczem. Zastosowałem takie rozwiązanie ponieważ nie wiedziałem czy wartości w pliku są unikalne.

    a tak btw. masz jakiś pomysł, jak póxniej zapisać nowe punkty do pliku, aby nie naruszyc jego struktury.. czy da się zaktualizowac tylko wiersz, gdzie występuje dany nick, czy trzebabędzie nadpisac cały plik?
    Hm, zawsze możesz zapisać bieżące punktu do pliku tymczasowego co będzie prostym rozwiązaniem nad podstawie informacji znajdujących się w samej tablicy asocjacyjnej. Jeśli zainteresowany jesteś zapisem w konkretne miejsce w pliku przydatna dla Ciebie będzie na pewno funkcja http://perldoc.perl.org/functions/seek.html.
    Ostatnio edytowane przez marcin. : 10-26-2008 - 13:47

  5. #5
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    Plik wejsciowy w formacie
    Kod:
    nick1=22
    nick2=436
    ...
    kod wczytujacy calosc
    Kod:
    use strict;
    my %users;
    
    open (IN, "users.txt") || die "Can't open users file: $!\n";
    while (<IN>) {
      chomp;
      /^(.*?)=(\d+)$/;
      $users{$1}=$2 if length($1)>0 and defined $2;
    }
    close (IN);
    Dlaczego zrobilbym to tak a nie inaczej?

    1. Regex bedzie szybszy niz seria operacji na tablicach
    2. Nie podano co moze byc nazwa usera - czy moga byc spacje czy cos jeszcze?
    3. Wiemy ze po = jest ilosc punktow i koniec
    4. Wpisanie danych do tablicy asocjacyjnej (hash'a) robimy tylko wtedy jesli nick ma dlugosc wieksza od zera i zdefiniowano ilosc punktow (ktora moze wynosic 0, dlatego uzylem and defined $2 zamiast and $2 bo to drugie wymagaloby aby ilosc punktow byla >0).

    Sprawdz kod - powniene dzialac

    P.S.
    Milo widziec nowe osoby zainteresowane pisaniem w Perlu - witam na pokladzie


    EDIT:
    Kod nie uwzglednia dopisywania wartosci do pliku (aktualizacja punktacji). Jesli mialby miec taka funkcje to proponuje zmienic linie

    Kod:
    $users{$1}=$2 if length($1)>0 and defined $2;
    na

    Kod:
    $users{$1}+=$2 if length($1)>0 and defined $2;
    Nie ma znaczenia czy wartosc istniala... zaczynamy z pustym hash'em i wiemy ze dla kazdego nowego klucza domyslna wartosc w tym kontekscie bedzie 0 wiec mozemy bezpiecznie dodawac do pliku kolejne linijki a pozniej skrypt w locie doda wszystkie punkty.

    Radze jednak uwazac z zapisywaniem do pliku - nie masz zadnej pewnosci, ze nie bedziesz mial na raz 2 userow, ktorzy odpala skrypt w tym samym czasie i obie kopie beda jednoczesnie pisac do pliku - rozwalajac go w ten sposob i powodujac utrate danych. Pewnie wiele osob powie, ze to malo prawdopodobne... no coz... ja mam inne doswiadczenia z takim podejsciem.
    Prawdopodobienstwo rosnie wprost proporcjonalnie do ilosci uzytkownikow. Raz stracilem juz spooora baze zrobiana w ten sposob. Od tej pory dla kazdego usera tworze osobny plik a pozniej w perlu wczytuje je pojedynczo i robie reszte.

    Co prawda zalozenie ze user bedzie w danej chwili mial tylko 1 proces dzialajacy tez jest bledne (juz z definicji) ale jesli cos spierdzieli to tylko sobie a nie wszystkim w systemie
    Polecam zapoznac sie z funkcja flock() w perlu i doczytac czy teraz dziala pod windows czy nie - powiem wprost, nie sadze aby windows to obslugiwal poprawnie.
    Ostatnio edytowane przez TQM : 10-26-2008 - 20:44
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

  6. #6
    Zarejestrowany
    Sep 2008
    Postów
    6

    Domyślnie

    Cytat Napisał TQM
    1. Regex bedzie szybszy niz seria operacji na tablicach
    Można polemizować.

    Swoją drogą dodam, że w Twoim kodzie idealnie widać naturę Perl-a, mianowicie chodzi o czytelność kodu. Bruce Eckel dobrze powiedział w swojej książcę, że Perl jest określany językiem tylko do napisania, a nie do czytania.

    :-)

  7. #7
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    Co do czytelnosci to nie zgodze sie niestety... tzn jest to w znacznej mierze kwestia gustu. Na przyklad zapis ktory podales bez linijki wyjasnienia (chocby commentu w kodzie co dany blok logicznie robi - tak jak to wyjasniles) dla mnie jest mniej zrozumialy niz 1 linijka ktora ja napisalem - moim zdaniem moj kod sie sam dokumentuje - mniej zmiennych, prosciej ogarnac logike.

    Oczywiscie jest so bardzo subiektywne podejscie i moznaby baaardzo dlugo dyskutowac co jest lepsze Do tego kazdy piszacy w perlu dochodzi sam, kazdy ma swoj styl. Stara prawda o Perlu - TIMTOWTDI (There Is More Than One Way To Do It).

    Co do wydajnosci, latwo sprawdzic... use Benchmark szczerze mowiac sam jestem ciekaw jak to wypadnie...

    Kod testowy wyglada tak:
    Kod:
    #!/usr/bin/perl
    use Benchmark qw(:all);
    my (%quiz, %users);
    my $input='user1=1';
    
    sub tablicami_by_marcin {
    	$_ = $input;
    	my @tmp = split(/=/, $_); 
    	if (scalar @tmp == 2) {
    		if (not defined $quiz{$tmp[0]}) { 
    			$quiz{$tmp[0]} = $tmp[1]; 
    		} else { 
    			$quiz{$tmp[0]} += $tmp[1];
    		}   
    	}
    	return
    }
    
    sub regexem_by_tqm {
    	$_ = $input;
    	chomp;
    	/^(.*?)=(\d+)$/;
    	$users{$1}+=$2 if length($1)>0 and defined $2;
    }
    
    # sprawdzamy czas pracy dla 2.5mln przebiegow
    my $result = timethese(2500000, {
    	'tablicami' => \&tablicami_by_marcin,
    	'regexami' => \&regexem_by_tqm,
    });
    
    # to tylko dla czytelnosci
    print "\n";
    
    # tabelka porownawcza
    cmpthese($result);
    A oto wyniki, aby sprawdzic dla innych ilosci przebiegow wystarczy zmienic licznik w timethese()

    Kod:
    $ ./benchmark-regex_vs_tablica.pl 
    Benchmark: timing 2500000 iterations of regexami, tablicami...
      regexami:  8 wallclock secs ( 8.14 usr +  0.00 sys =  8.14 CPU) @ 307125.31/s (n=2500000)
     tablicami:  8 wallclock secs ( 8.49 usr +  0.00 sys =  8.49 CPU) @ 294464.08/s (n=2500000)
    
                  Rate tablicami  regexami
    tablicami 294464/s        --       -4%
    regexami  307125/s        4%        --
    Hmmm 4% - zadziwiajaco mala roznica, przyznam ze spodziewalem sie wiecej
    Zajrzalem do dokumentacji i marcin - miasz duzo racji piszac kod w ten sposob... split jest szybsze niz regex, dalej porownania zmiennych, przypisania i if'y troche niweluja przewage jaka daje split vs regex.
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

  8. #8
    Zarejestrowany
    Sep 2008
    Postów
    6

    Domyślnie

    Cytat Napisał TQM
    Co do czytelnosci to nie zgodze sie niestety... tzn jest to w znacznej mierze kwestia gustu. Na przyklad zapis ktory podales bez linijki wyjasnienia (chocby commentu w kodzie co dany blok logicznie robi - tak jak to wyjasniles) dla mnie jest mniej zrozumialy niz 1 linijka ktora ja napisalem - moim zdaniem moj kod sie sam dokumentuje - mniej zmiennych, prosciej ogarnac logike.

    Oczywiscie jest so bardzo subiektywne podejscie i moznaby baaardzo dlugo dyskutowac co jest lepsze Do tego kazdy piszacy w perlu dochodzi sam, kazdy ma swoj styl. Stara prawda o Perlu - TIMTOWTDI (There Is More Than One Way To Do It).
    Zawsze mówiłem, zresztą tak samo myślę, że filozofia TIMTOWTDI jest zarówno przekleństwem oraz czymś naprawdę ciekawym. Tutaj nawiązuje do dużych projektów tworzonych w Perl-u.
    Cytat Napisał TQM
    Hmmm 4% - zadziwiajaco mala roznica, przyznam ze spodziewalem sie wiecej
    Zajrzalem do dokumentacji i marcin - miasz duzo racji piszac kod w ten sposob... split jest szybsze niz regex, dalej porownania zmiennych, przypisania i if'y troche niweluja przewage jaka daje split vs regex.
    :-) kiedyś robiłem podobne testy, także nie jestem zaskoczony wynikiem.

Podobne wątki

  1. [Perl] Kurs Perl - cz.1 - wprowadzenie i podstawy
    By TQM in forum Perl/Python/TCL/Prolog
    Odpowiedzi: 22
    Autor: 10-27-2014, 00:50
  2. Odpowiedzi: 18
    Autor: 07-14-2009, 11:55
  3. Odpowiedzi: 31
    Autor: 05-20-2008, 17:01
  4. logowanie
    By kalipawel in forum Off Topic
    Odpowiedzi: 6
    Autor: 10-17-2007, 10:09
  5. Odpowiedzi: 6
    Autor: 04-10-2007, 21:35

Zasady Postowania

  • Nie możesz zakładać nowych tematów
  • Nie możesz pisać wiadomości
  • Nie możesz dodawać załączników
  • Nie możesz edytować swoich postów
  •  
Subskrybuj