logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Dev-C++ – jak wyświetlać polskie znaki w konsoli, różne kodowanie CP1250/CP852

wrych 22 Lip 2009 22:36 26808 23
REKLAMA
  • #1 6811365
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    Pisząc kod źródłowy programu w Dev-C++ polskie znaki diakrytyczne (ą, ę ...) są kodowane w stronie kodowej CP1250. Po uruchomieniu programu w konsoli pojawiają się "krzaczki" - programy uruchamiane w konsoli wymagają strony kodowej CP852. Jak ten problem przeskoczyć?

    Mogę napisać program dokonujący konwersji znaków ale nie wiem jak go podpiąć do IDE.
  • REKLAMA
  • #2 6814057
    Dżyszla
    Poziom 42  
    Posty: 7077
    Pomógł: 1095
    Ocena: 226
    Każde wyświetlanie przekierować przez funkcję tłumaczącą (napisać samemu) z Win1250 na DOS852. W zależności od ustawienia funkcja może tłumaczyć bądź nie znaki diakrytyczne.
  • #3 6814552
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    Jeśli dobrze rozumiem, to kolega Dżyszla sugeruruje napisanie funkcji, która dokona zmiany kodu w trakcie pracy programu, czyli zamiast:
    cout << "Cześć";

    pisałbym
    cout << zmiana_kodu("Cześć");

    Jest to jakiś pomysł, ale nie oto mi chodziło. Problem pozostaje nadal otwarty...
  • REKLAMA
  • #5 6814948
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    W czasie gdy realizowałem pomysł podsunięty przez Dżyszlę, co wyszło mi mniejwięcej tak:
    
    #include <iostream>
    #include <string>
    using namespace std;
    
    string win2dos (string x)
    {
      int n = x.length();
      for (int i = 0; i < n; i++) {
          switch(x[i]) {
          case 'Ą': x[i]='¤'; break;
          case 'Ź': x[i]='Ť'; break;
          case 'Ć': x[i]='Ź'; break;
          case 'Ę': x[i]='¨'; break;
          case 'Ł': x[i]='ť'; break;
          case 'Ń': x[i]='ă'; break;
          case 'Ó': x[i]='ŕ'; break; 
          case 'Ś': x[i]='—'; break;     
          case 'Ż': x[i]='˝'; break;  
          case 'ą': x[i]='Ą'; break;
          case 'ć': x[i]='†'; break;
          case 'ę': x[i]='&copy;'; break;
          case 'ł': x[i]='ˆ'; break;
          case 'ń': x[i]='ä'; break;
          case 'ó': x[i]='˘'; break; 
          case 'ś': x[i]='˜'; break;
          case 'ź': x[i]='&laquo;'; break;
          case 'ż': x[i]='ľ'; break;
          };
          };  
      return (x);
    }
    
    int main ()
    {
      cout << "Problem polskich liter " << '\n';
      cout << "ąćęłńóśźż" << '\n';
      cout << "ĄĆĘŁŃÓŚŹŻ" << '\n';
      system("PAUSE");
      cout << win2dos("Próba rozwiązania wg pomysłu Dżyszli ") << '\n';
      cout << win2dos("ąćęłńóśźż") << '\n';
      cout << win2dos("ĄĆĘŁŃÓŚŹŻ") << '\n';
      system("PAUSE");
      return 0;
    }
    

    kolega Akane podał mi gotową funkcję. Dziękuję, ale to nadal nie jest to o co mi chodziło.
    Chciałbym, aby automatycznie (lub po naciśnięciu jakiegoś klawisza) przed kompilacją zmieniały się znaki kodowane w Windows na kodowane w Dos w całym pliku źródłowym. Podobnie jak w Notepad+ (przy kodowaniu HTML - polskie znaki Windows i ISO).

    Dodano po 11 [minuty]:

    Zrealizowałem program w oparciu o podpowiedź Akane
    
    #include <iostream>
    #include <windows.h>
    using namespace std;
    
    int main ()
    {
      cout << "Problem polskich liter " << '\n';
      cout << "ąćęłńóśźż" << '\n';
      cout << "ĄĆĘŁŃÓŚŹŻ" << '\n';
      system("PAUSE");
      char text[64]; 
      CharToOem("Próba rozwiązania wg podpowiedzi Akane ", text); 
      cout << text << '\n';
      CharToOem("ąćęłńóśźż", text); 
      cout << text << '\n';
      CharToOem("ĄĆĘŁŃÓŚŹŻ", text); 
      cout << text << '\n';
      system("PAUSE");
      return 0;
    }
    

    i wszystko działa jak należy. Ale jednak to nie jest to o co mi chodziło...
  • Pomocny post
    #6 6815041
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    Ja to rozwiązuję pisząc debugger dla kompilatora. W XP i wyżej, wpisując wartość debugger="mój_konwerter.exe" w kluczu HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\gcc.exe, zamiast gcc.exe uruchomi się mój_konwerter.exe, który podmienia znaki w pliku, uruchamia gcc.exe (z flagą DEBUG_PROCESS), czeka aż zakończy i przywraca oryginalny plik.
  • REKLAMA
  • #7 6815137
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    Akane, Twoja ostatnia odpowiedź jest zapewne tym o co mi chodziło. Ideę łapię, ale czy potrafię to zrealizować to się jeszcze okaże. Kiedyś pisałem w Pascalu taki program do konwersji plików:
    
    program WINto852;
    var
    f,g:text;
    znak:char;
    r:integer;
    nazwa,kopia:string;
    begin
    writeln('Konwersja plik˘w tekstowych z CP1250 do CP852 * (c) WR, 2008');
    nazwa:=paramstr(1);
    if nazwa='' then
    begin
     writeln('Wywoˆanie: winto852 plik1 plik2');
     writeln('Wywoˆanie: winto852 plik1');
     writeln('plik2 - domy˜lnie: txt-852.txt');
     exit;
    end;
    kopia:=paramstr(2);
    if kopia='' then kopia:='txt-852.txt';
    assign(f,nazwa);
    assign(g,kopia);
    {$I-}
    reset(f);
    rewrite(g);
    {$I+}
    if IOresult <> 0 then
    begin { sprawdza czy pliki zostaly otworzone }
    writeln ('BˆĄd otwarcia pliku: ', nazwa);
    exit;
    end;
    r:=0;
    while not eof(f) do
    begin
     read(f,znak);
       case znak of
       'Ą': znak:='¤';
       'Ź': znak:='Ť';
       'Ć': znak:='Ź';
       'Ę': znak:='¨';
       'Ł': znak:='ť';
       'Ń': znak:='ă';
       'Ó': znak:='ŕ';
       'Ś': znak:='—';
       'Ż': znak:='˝';
       'ą': znak:='Ą';
       'ć': znak:='†';
       'ę': znak:='&copy;';
       'ł': znak:='ˆ';
       'ń': znak:='ä';
       'ó': znak:='˘';
       'ś': znak:='˜';
       'ż': znak:='ľ';
       'ź': znak:='&laquo;';
       chr(133): begin write(g,'..'); znak:='.' end;
       chr(145): znak:=chr(39);
       chr(146): znak:=chr(39);
       end;
     write(g,znak);
    end;
    close(f);
    close(g);
    writeln('Przetworzono plik: ', nazwa);
    writeln('Wynik w  pliku: ', kopia);
    
    end.
    

    Co należało by zmienić (w sposobie przekazywania parametrów), aby wykorzystać ten program?
  • #8 6815294
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    Napisz to w C, będzie łatwiej o ile czujesz się na siłach. Zacznij od
    int main(int argc, char* argv[])

    argv[1] to namiar na gcc.exe
    argv[2] aż do argv[argc-1] to parametry przekazane do gcc. Jeden z nich to namiar pliku .cpp który musisz zmodyfikować. Upraszczając szukanie możesz sprawdzić czy argv[x] kończy się na ."cpp", w końcu to ma być na własny użytek.

    Gdy już znajdziesz parametr z namiarem na .cpp, wczytaj plik do pamięci i skocz do funkcji tokenizującej która albo stworzy jednokierunkową listę stringów (tokenów zaczynających się od cudzysłowia) albo lepiej dla każdego stringa wywoła funkcję która podmieni znaki w znalezionym stringu. Parsując tekst musisz pomijać komentarze // (\n przerywa jeżeli ostatni znak nie był ukośnikiem) oraz /* */, a szukając końca stringu musisz pomijać \".

    Gdy już wprowadzisz poprawki, zapisz plik pod tą samą nazwą (uprzednio kopiując oryginał) a następnie uruchom gcc funkcją CreateProcess. Linię poleceń zwróci funkcja PathGetArgs(GetCommandLine()), ale równie dobrze możesz jeszcze raz przelecieć całe argv[] pomijając pierwszą pozycję, zapisując sumę stringów w odpowiednio dużym buforze. Jeżeli użyjesz PathGetArgs, to zapisz wskaźnik w zmiennej i pomiń ewentualne spacje na początku. Zazwyczaj jest jedna.

    Teraz aby uruchamiając gcc nie uruchomić siebie samego, musisz albo usunąć wartość debugger z rejestru, albo użyć flagi DEBUG_PROCESS w funkcji CreateProcess. Wszystkie inne parametry dla CreateProcess ustaw domyślne - zazwyczaj NULL. Jeżeli zdecydujesz się na debugowanie to skocz do funkcji implementującej standardową pętlę debuggera - WaitForDebugEvent w pętli; EXIT_PROCESS_DEBUG_EVENT będzie oznaczało że gcc zrobił swoje.
    Jeżeli jednak zdecydujesz się nie debugować tylko usuniesz wartość debugger z rejestru, to zaczekaj aż gcc zrobi swoje funkcją WaitForSingleObject.

    Na koniec przywróć oryginalny plik .cpp, oraz przywróć wartość debugger w rejestrze jeżeli ją usunąłeś.

    * Niektóre programy widząc że są debugowane robią niespodzianki (breakpointy), wtedy warto ukryć debugger pewną sprytną funkcją.

    Mała uwaga co do lokalizacji w rejestrze. Nie gwarantuję, ale powinno zadziałać też w HKEY_CURRENT_USER - nigdy nie sprawdzałem.
  • #9 6815780
    Dr. Ma
    Poziom 12  
    Posty: 99
    Ocena: 3
    Ja myśle że po kompilacji należy zmienić to w konsoli i dupy se niezawracać. Poprzez właściwości na sztywno albo:

    \206 - ć
    \210 - ł
    \230 - ś
    \242 - ó
    \245 - ą
    \251 - ę
    \253 - ź
    \276 - ż
    \344 - ń

    cout<<"Cze\230\206";
  • REKLAMA
  • #10 6817788
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    Akane - dziękuję za obszerny i rzeczowy opis. Tego będę się trzymał...
    Jak będę miał problemy, to poproszę Cię o dalsze wskazówki.

    Dr. Ma - proponujesz "2 w 1":
    1) Ktoś komu dam skompilowany program może nie chcieć lub nie umieć dokonywać zmian w swojej konsoli.
    2) Druga wersja z kodami jest chyba lepsza, ale nie odpowiada mi taki kod źródłowy, np. do wydruku (fragment referatu w Wordzie).
    Dziękuję za zainteresowanie tematem.

    c.d.n.
  • Pomocny post
    #11 6818582
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    Wybacz, ale pokusiłem się na napisanie tego dla g++ - sprawdzone, działające. Gdybyś gdzieś ugrzązł to ściągnij i zerknij jak można to zrobić.
    Załączniki:
    • gcchook.c (6.51 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #12 6819070
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    Akane - dziękuję, ściągnąłem, zapisałem... i na razie nie zaglądam. Spróbuję sam powalczyć z tematem, wg Twoich wskazówek.

    A jednak zajrzałem (26.07.2009)... Miałem kłopoty z kompilacją, jednak dzięki wsparciu autora (Akane) wszystko gra. O to chodziło. Tematu na razie nie zamykam, może ktoś coś jeszcze ciekawego dorzuci.
  • Pomocny post
    #13 6850715
    Konto nie istnieje
    Konto nie istnieje  
  • #14 6854871
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    Dziękuję, funkcja "tr" działa poprawnie.
    Próbowałem poszukać coś o "wstringach" i znalazłem na jakimś forum:
    #include <wchar.h>
    #include <string>
    #include <iostream>
    using namespace std;
    int main (int argc, char * argv[]) {
    wstring x;
    wcout<<x;
    //wcout.imbue(locale("polish_Poland")); 
    //wcout<<L"zażółć gęślą jaźń ZAŻÓŁĆ GĘŚLĄ JAŹŃ"; 
    
    return 0;
    }

    Niestety wyskakuje błąd - funcja wcout jest niezadeklarowana.
  • #15 6857023
    Konto nie istnieje
    Konto nie istnieje  
  • #16 6857583
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    Radzi by zmienić kompilator no ale ja uparcie pozostaję przy Dev-C++ (jak w temacie). Już znalazłem kilka potwierdzeń na różnych forach, że Dev-C++ nie obsługuje poprawnie "wstringów"... Ale nadal tematu nie zamykam. Każdy kolejny post wnosi coś nowego. Kombinujmy dalej... chociaż muszę jeszcze raz stwierdzić, że rozwiązanie podane przez Akane załatwiło problem skutecznie!

    Dodano po 46 [minuty]:

    Zgodnie z radą zmieniłem kompilator (na chwilę)...

    1. Uruchomiłem: START | Uruchom: cmd
    2. Przeszedłem do folderu: D:\Program Files\Microsoft Visual Studio 8\VC\bin (tak to mam zainstalowane)
    3. Uruchomiłem edytor: "edit test.cpp" (kto z tego wynalazku jeszcze korzysta?)
    4. Zredagowałem tekst źródłowy programu (od razu w CP852) i zamknąłem edytor
    Dev-C++ – jak wyświetlać polskie znaki w konsoli, różne kodowanie CP1250/CP852
    5. Skompilowałem plik: "cl test.cpp /EHsc" i powstał efekt końcowy (test.exe)
    6. Uruchomiłem swój produkt: "test"

    Problemu z polskimi znakami nie było, bo odrazu zostały zapisane w stronie kodowej konsoli. Dłuższych programów jednak w ten sposób nie chciał bym pisać.
  • #17 6858310
    Konto nie istnieje
    Konto nie istnieje  
  • #18 6858604
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    Program pisałem na konsoli, aby w prosty sposób ominąć problem polskich liter (właściwie to problemu w tym przypadku nie było).
    Temat postu wyniknął stąd, że chciałem pisać w środowisku Dev-C++ lub Dev-Pascal programy dla konsoli z polskimi literami.
    Pisanie funkcji od podstaw to element nauki... Można wogóle korzystać z gotowych programów i nie uczyć się programowania.
  • #19 6858744
    Konto nie istnieje
    Konto nie istnieje  
  • #20 6988704
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    I jeszcze jedno rozwiązanie - pomysł powstał w wyniku przeglądania zasobów Internetu... Sprawdzone w Dev-C++:
    1. Napisane w C
    
    #include <stdlib.h>
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
        system("chcp 1250");
        system("CLS"); //można pominąć
        printf("ąćęłńóśźż\nĄĆĘŁŃÓŚŹŻ\n\n");
        system("PAUSE");
        return 0;
    }
    

    2. Napisane w C++
    
    #include <cstdlib>
    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        system("chcp 1250");
        system("CLS"); //można pominąć
        cout << "ąćęłńóśźż\nĄĆĘŁŃÓŚŹŻ\n\n";
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Program sam sobie zmienia stronę kodową konsoli. Wg uzyskanych informacji można edytując rejestr zmienić czcionkę w konsoli, ale tego jeszcze nie znalazłem.
  • #21 7012944
    U-235
    Poziom 12  
    Posty: 34
    Pomógł: 2
    Ocena: 6
    Ja znam bardzo prosty sposób na wyświetlanie polskich znaków w konsoli.
    Wszystko zawarte jest w kodzie ascii.
    dla przykładu:

    cout<<(char)143; // to literka Ć

    zamiesczam programik do odczytania numeru dowolnego znaku


    #include<iostream>
    using namespace std;
    void znaki_ascii()
    {
    for(int i=0;i<300;i++)
    {
    cout<<i<<". "<<(char)i<<endl;
    }
    }
    int main()
    {
    znaki_ascii();
    system("pause");
    }
  • #22 7015905
    wrych
    Poziom 20  
    Posty: 279
    Pomógł: 37
    Ocena: 22
    U-235 napisał:
    ... cout<<(char)143; // to literka Ć

    Z wcześniejszych postów wynika
    cout<<\217;  // to też literka Ć

    z tą tylko różnicą, że 217 jest kodem literki Ć w układzie ósemkowym, a napis \217 jest tu tym znakiem (ogólnie: \ooo - znak o kodzie w notacji ósemkowej).
    Twój sposób pozwala łatwiej wyświetlić tabelę znaków. Proponowałbym ograniczyć w pętli kody wyświetlanych znaków do kodu 255 (maksymalna wartoć Bajtu) i wyświetlać po kilka znaków w wierszu, np.:
    #include<iostream> 
    using namespace std; 
    void znaki_ascii() 
    { 
    for(int i=32;i<256;i++) 
    { 
      cout<<i<<". "<<(char)i<<" ";
      if (i%10==0) cout << endl;
    } 
    } 
    int main() 
    { 
      znaki_ascii();
      cout << endl; 
      system("pause"); 
    }

    Dziękuję za zainteresowanie tematem.
  • #23 17051352
    lszczygl
    Poziom 11  
    Posty: 7
    Pomógł: 1
    Ocena: 1
    setlocale(LC_CTYPE, "Polish");

    albo ogólnie

    setlocale(LC_ALL, "");
  • #24 17052276
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1464
    63404 napisał:

    Visual studio jest o tyle dobry ze ma rozbudowanego helpa i przyjemnie się w nim pisze programy. Minusem jest .NET wymagany do uruchomienia programów.


    Widocznie jeszcze nie zauwazyłęś, że Studio to platforma do przynajmniej kilku języków.
    Mało wiesz.

    63404 napisał:

    Aktualnie przechodzę na C++ Buildera (2009). Plusem jest to, że nie ma problemu z przenoszeniem programów na inne komputery które nie mają zainstalowanych żadnych dodatkowych bibliotek.


    Rada guzik warta w konsekwencji w/w
    Dodano po 1 [minuty]:
    lszczygl napisał:
    setlocale(LC_CTYPE, "Polish");

    albo ogólnie

    setlocale(LC_ALL, "");


    Locale nie ma (wbrew pokutującym w necie bajkom) wpływu na translację znaków.
    Dodano po 1 [minuty]:
    wrych napisał:

    2. Napisane w C++
    
    #include <cstdlib>
    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
    system("chcp 1250");
    system("CLS"); //można pominąć
    cout << "ąćęłńóśźż\nĄĆĘŁŃÓŚŹŻ\n\n";
    system("PAUSE");
    return EXIT_SUCCESS;
    }
    

    Program sam sobie zmienia stronę kodową konsoli. Wg uzyskanych informacji można edytując rejestr zmienić czcionkę w konsoli, ale tego jeszcze nie znalazłem.


    To nie jest C++, Mistrzu.
    Uruchamianie zewnętrznych programów jest bardzo zła polityką.

Podsumowanie tematu

LABEL_AI_GENERATED
Problem wyświetlania polskich znaków diakrytycznych w programach konsolowych pisanych w Dev-C++ wynika z różnicy stron kodowych: źródła kodowane są w CP1250 (Windows), natomiast konsola wymaga CP852 (DOS). Rozwiązania obejmują konwersję znaków w trakcie działania programu, np. za pomocą funkcji CharToOem lub własnych funkcji mapujących znaki z CP1250 na CP852. Proponowano także pisanie zewnętrznych konwerterów uruchamianych jako debugery lub modyfikujących pliki źródłowe przed kompilacją. Alternatywnie można zmienić kodowanie konsoli poleceniem systemowym chcp 1250, co pozwala na poprawne wyświetlanie polskich liter bez konieczności konwersji. Próby użycia wstringów i szerokich znaków w Dev-C++ napotykają na problemy, dlatego rekomendowane jest użycie innych kompilatorów, takich jak Microsoft Visual Studio 2008 lub CodeGear RAD Studio 2009, które lepiej obsługują Unicode i polskie znaki. Dyskusja podkreśla, że lepszym podejściem jest dostosowanie środowiska lub konsoli niż tworzenie od podstaw funkcji konwersji znaków. Wskazano także na możliwość zmiany czcionki konsoli i użycie kodów ASCII lub oktalnych do wyświetlania polskich liter. Podsumowując, najprostsze i skuteczne metody to zmiana kodowania konsoli na CP1250 lub użycie funkcji systemowych do konwersji znaków, a dla bardziej zaawansowanych – migracja do nowocześniejszych kompilatorów z lepszą obsługą Unicode.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA