[gelöst] boost::regex_replace und Umlaute

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
Heiko M.
Beiträge: 216
Registriert: 17.01.2005 12:31:34
Lizenz eigener Beiträge: MIT Lizenz

[gelöst] boost::regex_replace und Umlaute

Beitrag von Heiko M. » 08.03.2011 10:22:03

Wenn ich in C++ versuche alle Buchstaben eines Strings durch z.B. das Zeichen "*" via boost::regex_replace zu ersetzten, dann funktioniert das recht gut, solange der String keine Umlaute enthält. Treten jedoch Umlaute im String auf, dann wird jeder Umlaut mit "**" ersetzt, anstatt korrekterweise mit "*".

Folgendes Beispiel

Code: Alles auswählen

#include <iostream>                                                                                                                                              
#include <boost/regex.hpp>                                                                                                                                       
                                                                                                                                                                 
using namespace std;                                                                                                                                             
                                                                                                                                                                 
int main()                                                                                                                                                       
{                                                                                                                                                                
    string stringOrig = "abc.äöü";                                                                                                                               
    string charReplace = "*";                                                                                                                                    
    boost::regex pattern("\\w|[äöüÄÖÜß]");                                                                                                                       
                                                                                                                                                                 
    string stringMod = boost::regex_replace(stringOrig, pattern, charReplace);                                                                                   
                                                                                                                                                                 
    cout << "Original string: " << stringOrig << endl;                                                                                                           
    cout << "Modified string: " << stringMod << endl;                                                                                                            
                                                                                                                                                                 
    return 0;                                                                                                                                                    
}
ergibt diese Ausgabe:

Code: Alles auswählen

Original string: abc.äöü
Modified string: ***.******
Woran könnte das denn liegen?
Zuletzt geändert von Heiko M. am 17.03.2011 08:44:55, insgesamt 1-mal geändert.
Debian Testing (amd64) + KDE

Benutzeravatar
bmario
Beiträge: 1257
Registriert: 05.09.2007 12:15:47
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Dresden

Re: boost::regex_replace und Umlaute

Beitrag von bmario » 08.03.2011 15:28:19

Umlaute sind keine ASCII Chars, also kommt es drauf an, mit welcher Codierung gearbeitet wird. Da es vermutlich UTF-8 ist, schau mal hier:
http://www.utf8-zeichentabelle.de/ die Umlaute belegen also zwei Byte, also zwei char und auf char basiert std::string. (*edit: Also wird ein Umlaut folgerichtig als zwei Zeichen behandelt.) Benutze also mal std::wstring oder schau dich mal in GUI Frameworks wie QT oder gtkmm um. (Für gtkmm gibt's den glib::ustring) Alternativ ersetzte die Umlaute vorher durch a,u,o ;)
Nichts zu tun ist viel besser,
als mit viel Mühe nichts zu schaffen. - Laotse

Benutzeravatar
Heiko M.
Beiträge: 216
Registriert: 17.01.2005 12:31:34
Lizenz eigener Beiträge: MIT Lizenz

Re: boost::regex_replace und Umlaute

Beitrag von Heiko M. » 09.03.2011 12:51:02

Danke für den Hinweis und ja, Codierung ist UTF-8. Hab mal ein wenig mit wstring rumgespielt, aber das will auch nicht so recht. Scheitere schon an dem einfachsten Beispiel

Der Code

Code: Alles auswählen

#include <iostream>                                                                                                                                              
                                                                                                                                                                 
using namespace std;                                                                                                                                             
                                                                                                                                                                 
int main()                                                                                                                                                       
{                                                                                                                                                                
    wstring wstr = L"abc.äöü";                                                                                                                           
                                                                                
    wcout << wstr << endl;                                                                                                          
                                                                                                                                                                 
    return 0;                                                                                                                                                    
} 
ergibt folgende Ausgabe:

Code: Alles auswählen

abc.???
Liegt das eventuell am Terminal und der Codierung UTF-8? Muss man für eine korrekte Ausgabe eines wstrings eventuell UTF-16 benutzen?
Das ist Quatsch, wie ich gerade festgestellt habe. Dachte UTF-8 würde ein Byte (8bit) pro char verwenden und schloss daraus, dass UTF-16 zwei Byte (16bit) verwenden würde. Ist aber nicht so.

http://de.wikipedia.org/wiki/UTF-8 sagt:
UTF-8 unterstützt bis zu vier Byte ...
Weshalb stellt das Programm / die Konsole nun die Umlaute eines wstring als Fragezeichen dar?
Debian Testing (amd64) + KDE

Benutzeravatar
Heiko M.
Beiträge: 216
Registriert: 17.01.2005 12:31:34
Lizenz eigener Beiträge: MIT Lizenz

Re: boost::regex_replace und Umlaute

Beitrag von Heiko M. » 17.03.2011 08:44:29

So, hatte heute früh wieder etwas Zeit, mich mit meinem Problem auseinanderzusetzen. Die Lösung besteht darin, mit "locale" die passende Lokalisierung/Codierung zu setzten. Dann klappst auch wunderbar mit wstring und man kann auf den OR-Operator "|[äöüÄÖÜß]" in regex verzichten.

Der Code sieht dann so aus

Code: Alles auswählen

#include <iostream>                                                                                                                                              
#include <boost/regex.hpp>                                                                                                                                       
#include <locale>                                                                                                                                                
                                                                                                                                                                 
using namespace std;                                                                                                                                             
                                                                                                                                                                 
int main()                                                                                                                                                       
{                                                                                                                                                                
    locale::global(locale("de_DE.UTF-8"));
                                                                                                                       
    wstring stringOrig = L"abc.äöüß";                                                                                                                             
    wstring charReplace = L"*";                                                                                                                                  
    boost::wregex pattern(L"\\w");                                                                                                                     
                                                                                                                                                                 
    wstring stringMod = boost::regex_replace(stringOrig, pattern, charReplace);                                                                                  
                                                                                                                                                                 
    wcout << "Original string: " <<stringOrig << endl;
    wcout << "Modified string: " << stringMod << endl;                                                                                                           
                                                                                                                                                                 
    return 0;                                                                                                                                                    
}

und ergibt das gewünschte Resultat:

Code: Alles auswählen

Original String: abc.äöüß
Modified string: ***.****
Vielen Dank nochmal für den Hinweis auf wstring. Feine Sache.
Debian Testing (amd64) + KDE

Antworten