• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Kdowanie UTF-8 w Visual Studio C++ 2017 (polskie znaki)

Object Storage Arubacloud
0 głosów
7,295 wizyt
pytanie zadane 26 grudnia 2017 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 26 grudnia 2017 przez Jakub 0

Hej, wiem że jako tako jest dużo pytań na temat polskich znaków, nie znalazłem jednak nic co by mi działało :X. Mianowicie koledzy ze szkoły "udając mądrych" pisali życzenia w systemie binarnym, ja by stać się jeszcze mądrzejszym (po tym pytaniu widać że tak nie jest) napisałem program konwertujący znaki zapisane w systemie binarnym na zrozumiały tekst. O ile bez jakiś większych problemów zrobiłem interpreter bin->dec (i wszystko działa tu ok) to zniszczyła mnie ta kwestia kodowania znaków... Korzystałem z takiej tabeli ASCI (zastępowałem znaki polskie odpowiednimi ich kodami):

Okazało się jednak że tekst był zapisany z wykorzystaniem UTF-8, moje IDE go nie obsługuje (nie wiem gdzie w ogóle zmienić kodowanie). Zrobiłem masę if'ów przetwarzających kod polskich symboli z UTF-8 na tą tabelkę która mi działa poprawnie. To jednak nic nie daje, korzystałem z mnóstwa instrukcji i funkcji (local, global, wchar, wcout itd...) Nic jednak u mnie nie działa. Jakaś masakra, pokonałem problem jakim było stworzenie algorytmu przeliczającego systemy a teraz wysiadam przy systemach kodowania. Czy jest jakiś sensowny sposób by pozbyć się tego problemu. Czy na prawdę w XXI wieku są kłopoty z kodowaniem znaków? Że trzeba robić funkcje, makra itd... Wiem że to ja tego w ogóle nie rozumiem i to raczej moja wina, będę wam bardzo wdzięczny za pomoc . Reasumując chcę by program kodował znaki w UTF-8 w tym polskie.

Przepraszam jeśli coś źle napisałem i jeszcze raz dziękuje za chęć pomocy :) :

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <conio.h>
#include <string>
#include <cmath>


char to_result(std::string str_bin) { //konwersja dziala ok ale:
	int result = 0;
	int c = 0;
	 
	for (int i = str_bin.length() - 1; i >= 0; i--) {
		if(str_bin[i]!='0'){
			result += pow(2, c);
		}c++;
	}

	return char(result); //tu probowalem wiele metod, mialem tu z 20 if'ow ale skasowalem. Tutaj zwracamy odpowiedni znak w zaleznosci od liczby w dec
}

int main()
{
	///////////////////input 

	int n;
	std::vector<std::string>vec;

	std::cout << "podaj ilosc liczb: ";
	std::cin >> n;

	for (int i = 0; i < n; i++) {
		std::string temp; std::cin >> temp;
		vec.push_back(temp);
	}

	//////////////////output

	std::cout << "output: " << std::endl;

	for (auto iterator : vec) {
		std::cout << to_result(iterator); //zwracanie pojedynczych znakow 
	}

	std::cout << std::endl;

	return 0;

	_getch();
}

 

komentarz zamknięcia: już działa

1 odpowiedź

+3 głosów
odpowiedź 26 grudnia 2017 przez Sebastian Fojcik Nałogowiec (43,040 p.)
wybrane 26 grudnia 2017 przez criss
 
Najlepsza

Witaj,

Twój problem wynika z tego, że w UTF-8 znaki mogą być kodowane nie na jednym, a na kilku (nawet sześciu!) bajtach. Polskie znaki są kodowane przez 2 bajty. Zmienna char przechowuje 1 bajt. 

Najlepiej będzie jeśli polskie znaki przechowasz w zmiennej wchar_t. Ta zmienna przechowuje długie znaki (wide characters) złożone z dwóch bajtów. I powinieneś właśnie w ten sposób zakodować polskie znaki.

Przyjrzyj się plikowi, który zawiera tekst "Wesołych świąt" w Hex Edytorze. Załączam zdjęcie:

Jak widzisz litera 'ł' jest zakodowana na dwóch bajtach C5 oraz 82 (to są notacje szesnastkowe). Te dwa bajty złączone razem tworzą liczbę. Jeśli potraktujesz ją jako liczbę ze znakiem, to będzie to -14974. Jeśli bez znaku, to 50562. Tak więc chcąc zapisać polski znak do pliku musiałbyś tam wysłać strumieniem 2 znaki char o wartości C5 (czyli 197) oraz 82 (czyli 130). Coś takiego:

Jak widzisz do zapisania litery 'ł' musiałem 2 wartości (bajty) wysłać. Od razu uprzedzam, że Twojego zakodowanego tekstu nie wyświetlisz w konsoli jak to próbujesz teraz zrobić. Konsola nie koduje liter w UTF-8. Rezultat kodowania musisz zapisać do pliku i wtedy notatnik wspierający UTF-8 poprawnie wyświetli litery.

Pozdrawiam serdecznie.

Pytaj w razie problemów jeszcze :-)

komentarz 26 grudnia 2017 przez Jakub 0 Pasjonat (23,120 p.)

Wielkie dzięki za zbliżenie mi tematu, nie chce nadużywać cierpliwości ale coś znowu zawaliłem:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <conio.h>
#include <string>
#include <cmath>
#include <fstream>

//46 - taka dla mnie notka ile liter ma zdanie :) 

wchar_t to_result(std::string str_bin) { //większy zakres, zrozumiałem że dzięki niemu nie będę musiał kodować znaku w kilku charach
	int result = 0;
	int c = 0;
	 
	for (int i = str_bin.length() - 1; i >= 0; i--) {
		if(str_bin[i]!='0'){
			result += pow(2, c);
		}c++;
	}

	return wchar_t(result);
}

int main()
{
	///---------------------------------------------------------------input 

	int n;
	std::vector<std::string>vec;

	std::cout << "podaj ilosc liczb: ";
	std::cin >> n;

	for (int i = 0; i < n; i++) {
		std::string temp; std::cin >> temp;
		vec.push_back(temp);
	}

	///----------------------------------------------------output

	std::ofstream file("result.txt"); //zapis do pliku 

	for (auto i : vec) {
		file << wchar_t(to_result(i)); ..użyłem rzutowania, chyba nic to teraz nie zmienia 
	}

	return 0;
}

Ale dalej jest dziwnie, teraz mi się w ogóle liczby zapisują do pliku (pewnie kody znakowe). Dlaczego tak jest? Raz coś zrobiłem że zostały tam wpisane znaki, już nie pamiętam co... (ale i tak nie polskie). Tutaj cały efekt działania programu:

Wiem że coś jak zwykle źle zrozumiałem...

komentarz 26 grudnia 2017 przez Jakub 0 Pasjonat (23,120 p.)
problem może też być chyba w mojej obsłudze funkcją ofstream (czytam teraz na jej temat bo nigdy o niej nie słyszałem, korzystałem zawsze  z fstream).
2
komentarz 26 grudnia 2017 przez criss Mędrzec (172,590 p.)
edycja 26 grudnia 2017 przez criss

Do pliku musisz pisać bajt po bajcie. Zobacz jak to zrobił Sebastian, żeby zapisać 'ł': najpierw 0xC5, potem 0x82. Ty piszesz jedną liczbę dwubajtową na raz, co jest inaczej traktowane przez fstream.

... Czyli do zapisu użyć typu char. Funkcje to_result możesz zostawić, tylko w przypadku wyniku >127 załatwić to nieco inaczej, a w przypadku <=127 wynik rzutować na char. Nieco inaczej czyli bajt po bajcie. Do tego proponuje np. takie makra:

#define HI(n) char((n & 0xff00) >> 8) // starszy bajt jako char
#define LO(n) char(n & 0xff) // mlodszy bajt jako char
1
komentarz 26 grudnia 2017 przez Sebastian Fojcik Nałogowiec (43,040 p.)

Trochę źle mnie zrozumiałeś. Wczytywanie jest OK. Tylko jak wczytujesz liczbę binarną, jeden bajt, to od razu musisz go od razu zamienić na liczbę dziesiętną, zapisać do zmiennej char i wpisać do pliku. Nie używaj wchar_t do tego, być może niepotrzebnie Cię zmyliłem. 

Tak swoją drogą, to jest gotowa funkcja do zamiany kodu binarnego na liczbę. Ogólnie fajnie, że napisałeś swoją funkcję, ale programiści są raczej z natury leniwi. Funkcja stoi( string, 2) zamienia string na Int. Potem tylko rzutujesz na char i wpisujesz do pliku. 

string bin; 
cin >> bin; //podajesz 8 bitów, np. 01100001 
int dec = stoi( bin, 2 );
plik << (char)dec; 

Pisze to z telefonu, więc nie mam możliwości sprawdzić, więc wybacz. 

Daj znać czy udało Ci się rozwiązać problem :-)

1
komentarz 26 grudnia 2017 przez Jakub 0 Pasjonat (23,120 p.)

Jest!!!! Wreszcie się udało... Nawet nie wiesz jak się ciesze :) Nawet nie sądziłem że to można tak prosto zrobić, myślałem  że najtrudniejsze będzie konwertowanie bin na dec a polskie znaki to luzik... a było na odwrót. Funkcje jednak zostawiłem własną bo coś to stoi mi nie chciało działać. Uczę się teraz c++ z książki c++ Szkoła programowania i mam nadzieje że niedługo znajdę informacje też na te tematy. Jeszcze raz bardzo dziękuje i serdecznie pozdrawiam laugh

1
komentarz 26 grudnia 2017 przez Sebastian Fojcik Nałogowiec (43,040 p.)

To świetnie, że rozwiązałeś problem :-D

Do stoi musisz pisać w standardzie C++11 i dołączyć nagłówek #include <string>

Twórz więcej takich swoich mini-wyzwań, a wiedza będzie sama wpadać przy okazji realizowanych projektów. 

Powodzenia :-)

Podobne pytania

0 głosów
0 odpowiedzi 123 wizyt
pytanie zadane 21 marca 2019 w C i C++ przez MrChick888 Obywatel (1,020 p.)
0 głosów
1 odpowiedź 221 wizyt
pytanie zadane 16 października 2018 w C i C++ przez bart987 Nowicjusz (140 p.)
0 głosów
1 odpowiedź 300 wizyt

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...