ページ 1 / 1
stringでの日本語の使い方
Posted: 2012年1月06日(金) 20:18
by Cr
c++です。
stringで日本語の文章を入力し、それを逆にして返すというプログラムが書きたかったのですがうまくいきません
入力が「日本語の文章」なら出力は「章文の語本日」としたいです。
コード:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(1){
cin >> str;
if(str=="END") return 0;
do{
cout << str.substr(str.size()-1);
str.erase(str.size()-1);
}while(!str.empty());
cout <<endl;
}
}
これをコンパイルして実行したところ英語の分に対しては正しい出力がされましたが日本語では無理でした
たとえば
C言語→鼬セ靴
あいうえお→ィえういあ
漢字とひらがなを使う→、H酒ながらひとz質
といった具合です。
試しにひっくり返さずにそのまま出力する命令を前に入れたところ文字化けは起こりませんでした
確か日本語は英語より使ってる領域が多かった覚えがあり、それが関係しているのだろうと予測しています。
日本語でこの機能を満たすことは可能でしょうか?
Re: stringでの日本語の使い方
Posted: 2012年1月06日(金) 20:43
by Cr
追記です
文字化けしたものをもう一回プログラムにかけてみたらこうなりました
鼬セ靴→C言語
、H酒ながらひとz質→ソ字とひらがなを使う
ィえういあ→いうえお
最初の文字だけはアルファベット以外うまくいかないみたいですが、他の文字は元に戻りました。
Re: stringでの日本語の使い方
Posted: 2012年1月06日(金) 20:51
by non
SHIFT-JISなら、漢字は2バイトなので、
str.size()-2 にして試してみたら。
注:半角を混ぜると暴走するかも。
Re: stringでの日本語の使い方
Posted: 2012年1月06日(金) 21:06
by softya(ソフト屋)
wstring他のワイド文字系で統一すれば問題ないと思います。
Re: stringでの日本語の使い方
Posted: 2012年1月06日(金) 22:16
by たかぎ
softya(ソフト屋) さんが書きました:wstring他のワイド文字系で統一すれば問題ないと思います。
std::wstringだと処理系に依存しますし、std::u16stringだとサロゲートペアが問題になります。
std::u32stringであれば、次のように、簡単に文字列を反転することができます。
コード:
std:u32string str(U"日本語の文章");
std::reverse(str.begin(), str.end());
ただし、標準入力や標準出力を扱うのはちょっと面倒になります。
(処理系を特定するなら、ほとんどの場合、そう難しくありません)
Re: stringでの日本語の使い方
Posted: 2012年1月06日(金) 22:19
by みけCAT
とりあえず作ってみました。
► スポイラーを表示
コード:
#include <iostream>
#include <string>
/*使用する文字コードに応じて定義する*/
#define SHIFT_JIS
/*#define EUC*/
/*#define UTF_8*/
/*
参考
http://ash.jp/code/code.htm
*/
/*次の一文字のバイト数を判定する*/
/*Shift-JIS用*/
#ifdef SHIFT_JIS
int mozilen_hantei(const unsigned char* moziretu) {
/*文字列終端*/
if(moziretu[0]==0)return 0;
/*次が文字列終端*/
if(moziretu[1]==0)return 1;
if(
(
(moziretu[0]>=0x81 && moziretu[0]<=0x9F) ||
(moziretu[0]>=0xE0 && moziretu[0]<=0xEF)
) && (
(moziretu[1]>=0x40 && moziretu[1]<=0x7E) ||
(moziretu[1]>=0x80 && moziretu[1]<=0xFC)
)
)return 2;
/*その他*/
return 1;
}
#endif
/*EUC用*/
#ifdef EUC
int mozilen_hantei(const unsigned char* moziretu) {
/*文字列終端*/
if(moziretu[0]==0)return 0;
/*次が文字列終端*/
if(moziretu[1]==0)return 1;
if(moziretu[0]==0x8E && (moziretu[1]>=0xA1 && moziretu[1]<=0xDF))
return 2;
if(
(moziretu[0]>=0xA1 && mozireut[0]<=0xFE) &&
(moziretu[1]>=0xA1 && moziretu[1]<=0xFE)
)return 2;
if(
moziretu[0]==0z8F &&
(moziretu[1]>=0xA1 && moziretu[1]<=0xFE) &&
(moziretu[2]>=0xA1 && moziretu[2]<=0xFE) &&
)return 3;
/*その他*/
return 1;
}
#endif
/*UTF-8用*/
#ifdef UTF_8
int mozilen_hantei(const unsigned char* moziretu) {
int max,result;
for(max=0;max<6;max++) {
if(moziretu[max]==0)break;
}
result=1;
if((moziretu[0] & 0x80)==0x00)result=1;
else if((moziretu[0] & 0xE0)==0xC0 && max>=2) {
if((moziretu[1] & 0xC0)==0x80)result=2;
} else if((moziretu[0] & 0xF0)==0xE0 && max>=3) {
if((moziretu[1] & 0xC0)==0x80 &&
(moziretu[2] & 0xC0)==0x80)result=3;
} else if((moziretu[0] & 0xF8)==0xF0 && max>=4) {
if((moziretu[1] & 0xC0)==0x80 &&
(moziretu[2] & 0xC0)==0x80 &&
(moziretu[3] & 0xC0)==0x80)result=4;
} else if((moziretu[0] & 0xFC)==0xF8 && max>=5) {
if((moziretu[1] & 0xC0)==0x80 &&
(moziretu[2] & 0xC0)==0x80 &&
(moziretu[3] & 0xC0)==0x80 &&
(moziretu[4] & 0xC0)==0x80)result=5;
} else if((moziretu[0] & 0xFE)==0xFC && max>=6) {
if((moziretu[1] & 0xC0)==0x80 &&
(moziretu[2] & 0xC0)==0x80 &&
(moziretu[3] & 0xC0)==0x80 &&
(moziretu[4] & 0xC0)==0x80 &&
(moziretu[5] & 0xC0)==0x80)result=6;
}
if(result>max)result=max;
return result;
}
#endif
int main(void) {
std::string inputstr;
std::string outputstr;
const char* input;
int* onelength;
char* output;
int i,j,len,inputmax;
/*入力*/
std::getline(std::cin,inputstr);
inputmax=inputstr.size();
input=inputstr.c_str();
onelength=new int[inputmax];
output=new char[inputstr.size()+100];
/*半角と全角の判定*/
for(i=0;i<inputmax;) {
len=mozilen_hantei((const unsigned char*)&input[i]);
onelength[i]=len;
for(j=1;j<len;j++)onelength[i+j]=0;
if(len<=0)len=1;/*無限ループ防止*/
i+=len;
}
/*出力文字列の準備*/
len=0;
for(i=inputmax-1;i>=0;i--) {
if(onelength[i]>0) {
for(j=0;j<onelength[i];j++) {
output[len+j]=input[i+j];
}
len+=onelength[i];
}
}
output[len]=0;
outputstr=output;
/*メモリ開放*/
delete onelength;
delete output;
/*出力*/
std::cout << outputstr << std::endl;
/*正常終了*/
return 0;
}
Re: stringでの日本語の使い方
Posted: 2012年1月06日(金) 23:19
by Cr
non さんが書きました:SHIFT-JISなら、漢字は2バイトなので、
str.size()-2 にして試してみたら。
注:半角を混ぜると暴走するかも。
一回試してみました
日本語はうまく行きました!
ただやっぱりアルファベット混ぜると無理ですね…
softya(ソフト屋) さんが書きました:
wstring他のワイド文字系で統一すれば問題ないと思います。
マルチバイト自体が初耳でして
一応いろいろ調べてみたのですが…
ちょっと実装するには先が長そうです…
たかぎ さんが書きました:
std::wstringだと処理系に依存しますし、std::u16stringだとサロゲートペアが問題になります。
std::u32stringであれば、次のように、簡単に文字列を反転することができます。
同じく初耳です
wstringの方を理解してから調べたいと思います…
みけCAT さんが書きました:
とりあえず作ってみました。
何やってるかはなんとなく分かりました
細かい仕組みは分かりませんが…
とりあえずチャットの方で教えていただいた情報も参考に、
先頭からその文字が1バイトかかどうか判断し、その分を別のstringの先頭にひたすら足していくという方法で作ってみました。
文字コードなど、細かいことはまだ分かっていませんが一応実行結果はでました。
コード:
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
int main(){
string str;
char c;
while(1){
cin >> str;
string answer;
if(str=="END") return 0;
do{
c = str[0];
if(IsDBCSLeadByte(c)==0){
answer.insert(0,str.substr(0,1));
str.erase(0,1);
}else{
answer.insert(0,str.substr(0,2));
str.erase(0,2);
}
}while(!str.empty());
cout <<answer <<endl;
}
}
入力 日本語とEnglish
出力 hsilgnEと語本日
入力 あaいiうuえeおo
出力 oおeえuうiいaあ
望む動きはできたので解決としたいと思います
マルチバイト等の単語についてはテスト明けにゆっくり調べたいと思います。
みなさんどうもありがとうございました!