C言語orC++言語で日本語の処理がしたいのですが方法がわかりません。
以下のlen,mid関数を作成したいのですが、どうすればよいのでしょうか。
文字コードはSJIS(CP932?)とします。
また、C言語のソースは基本的にSJIS書き、コンパイルすると解釈してよいですか?WindowsはSJIS? LinuxはEUC-JP??
#include <stdio.h>
#include <string.h>
void main(void){
char moji[] = "パソコンでABC";
// この結果は「パソコンでABC」, 19, 18で正しいです。
printf("%s\n%d\n%d", moji, sizeof(moji), strlen(moji));
// 文字数換算で8と出力させる方法
// 汎用関数 Len関数を作る Lenbでない。この場合 len(moji)の結果は「8」
// 文字数換算で6文字目から3文字数カットしたABCを出力する。
// 汎用的に MID関数を作る MIDBでない。この場合 mid(moji, 3, 5)の結果は 「コンでABC」
}
あと、詳しい書籍等もご存知の方教えてください。
No.6ベストアンサー
- 回答日時:
参考までにGNU C++の場合を書いてみます。
ソースファイルでCP932を使う場合、コンパイルオプションで-finput-charset=cp932を指定する必要があります。実行文字コードは、ロケールにあわせて-fexec-charsetで指定してください。(デフォルトではUTF-8になります)
内部的な処理は、多バイト文字列のままでは面倒なので、いったんワイド文字列に変更します。mbstowcs等で変換するか、libiconvでも使いましょう。(もちろん、ICUなどの外部ライブラリでもOKですし、std::codecvtファセットを使ってもOK)
ワイド文字列になってしまえば、あとはstd::wstringを使えば簡単です。
VBのLenは、std::wstring::sizeまたはstd::wstring::lengthを使います。
VBのMidは、std::wstring::substrを使うか、std:wstringのコンストラクタで対応できます。
以下、未検証ですが、コードをのせておきます。
#include <iostream>
#include <string>
#include <locale>
#include <clocale>
#include <cstdlib>
int main()
{
std::setlocale(LC_CTYPE, "");
std::wcout.imbue(std::locale(""));
wchar_t wcs[16];
mbstowcs(wcs, "パソコンでABC", sizeof(wcs)/sizeof(wcs[0]));
std::wstring moji(wcs);
std::wcout << L"Len(moji): " << moji.length() << std::endl;
std::wcout << L"Mid(moji, 3, 5): << moji.substr(3, 5) << std::endl;
}
この回答への補足
8は表示されましたが、以下は何も表示されませんでした。
ちなみに"が抜けていましたので、付加しています。 [, 3, 5):]
std::wcout << L"Mid(moji, 3, 5):" << moji.substr(3, 5) << std::endl;
substrを返す型が base_string型?なので、printf("%s", moji.substr(3, 5));でも表示されません。
STL?は難しいですね。
良い書籍も探しています。
No.5
- 回答日時:
★追記。
・前回の(1)~(4)をサンプルとして載せておく。
なお、実際には C++ のクラスとして作ればよい。
MFC の CString 型と同じような使い方になるように。
ちなみに CString 型でも Unicode 文字を扱えます。
// 独自の文字型
typedef unsigned short JAPANCODE;
// 漢字の第1文字の判定
#define isKanji(c) ((unsigned int)(((unsigned char)(c) ^ 0x20) - 0xA1) < 0x3C)
サンプル1:SJIS文字列から独自文字列に変換
JAPANCODE *tobasu_ToJapan( JAPANCODE japan[], const char string[] )
{
JAPANCODE *j = japan;
const char *p = string;
while ( *p != '\0' ){
if ( isKanji(*p) ){
*j++ = ((JAPANCODE)p[0] << 8) | p[1];
p += 2;
}
else{
*j++ = *p++;
}
}
*j = 0x0000;
return japan;
}
サンプル2:独自文字列からSJIS文字列に変換
char *tobasu_ToSjis( JAPANCODE japan[], char buff[] )
{
JAPANCODE *j = japan;
char *p = buff;
while ( *j != 0x0000 ){
if ( *j > 0x100 ){
*p++ = (char)(*j >> 8);
}
*p++ = (char)(*j >> 0);
j++;
}
*p = '\0';
return buff;
}
サンプル3:独自文字列の長さ取得
size_t tobasu_Len( JAPANCODE japan[] )
{
JAPANCODE *p;
for ( p = japan ; *p != 0x0000 ; p++ ){
;
}
return (size_t)(p - japan);
}
※tobasu_LenBというバイト長の関数も用意した方が良いかも。
サンプル4:独自文字列の中間取り出し
JAPANCODE *tobasu_Mid( JAPANCODE japan[], JAPANCODE middle[], int pos, int n )
{
JAPANCODE *j = japan + pos - 1;
JAPANCODE *p = middle;
if ( j < (japan + tobasu_Len(japan)) ){
while ( (n > 0) && (*j != 0x0000) ){
*p++ = *j++;
n--;
}
}
*p = 0x0000;
return middle;
}
使い方:
int main( void )
{
JAPANCODE moji[ 100 ];
JAPANCODE mid[ 100 ];
char buff[ 200 ];
// SJISをセット
tobasu_ToJapan( moji, "パソコンでABC" );
// 文字列
printf( "Str=%s\n", tobasu_ToSjis(moji,buff) );
// 文字数
printf( "Len=%d\n", tobasu_Len(moji) );
// 取り出し
tobasu_Mid( moji, mid, 3, 5 );
printf( "Mid=%s\n", tobasu_ToSjis(mid,buff) );
return 0;
}
以上。
No.4
- 回答日時:
★Unicode文字を使わないなら次の方法は。
・SJISコード体系で半角文字、全角文字のそれぞれ1文字を unsigned short 型で表現します。
この型の配列で文字列を表現する簡易版の日本語処理ライブラリを用意します。
用意する関数群としては
(1)SJIS文字列から独自文字列に変換
(2)独自文字列からSJIS文字列に変換
(3)独自文字列の長さ取得(Len)
(4)独自文字列の中間取り出し(Mid)
(5)独自文字列のコピー
(6)独自文字列の比較
(7)独自文字列の検索
その他はいろいろと独自文字列の処理関数を用意します。
その他:
・本当なら内部では Unicode 文字体系で処理をして入出力を SJIS コードの
相互変換する仕組みにすればいいと思います。
Windows 系や Unix 系の両方で動かすなら Unicode 文字をお勧めします。
Unicode 文字を使えば上記のライブラリは特に必要ないです。
Unicode 文字を操作する関数群が用意されていますので。
ただし BASIC で用意されている MID、MIDB はご自分で用意して下さい。
MID のような関数はないので。
・以上。
No.3
- 回答日時:
汎用関数 Len関数を作ってみました。
半角文字、全角文字が混ざっていても数えられるようにしてみました。#include <stdio.h>
#include <string.h>
int Len(char *moji);
int main(void)
{
char moji[] = "パソコンでABCabc1009";
printf("%s\n%d\n%d\n", moji, sizeof(moji), strlen(moji));
printf("文字数換算 : %d\n", Len(moji));
return 0;
}
/* 文字数換算 自作関数 */
int Len(char *str)
{
int mojisuu = 0;
while(*str){
/*-------------------------------------------
2バイト文字は1バイト目の値が
0x81~0x9fまたは0xe0~0xfcという
ルールを使用して判定してます。
参考URL:http://tokyo.cool.ne.jp/sdl/index9.html
-------------------------------------------*/
if (0x81 <= *str && *str <= 0x9f || 0xE0 <= *str && *str <= 0xFC) {
str += 2;
} else {
str += 1;
}
printf("%s\n", str); /* 処理内容確認のため いらなければコメントアウトで。。。*/
mojisuu++;
}
return mojisuu;
}
参考URL:http://tokyo.cool.ne.jp/sdl/index9.html
No.2
- 回答日時:
#include <stdio.h>
// mid(元文字列バッファ、開始位置、範囲文字数、結果バッファ、バッファサイズ)
int mid(const char* inStr,short start,short range,char *outStr,int cSize)
{
int i,j,seek;
if (cSize<=range || start<=0) return 0;
for (i=0,seek=1;seek-start;i+=(inStr[i]<0x20||inStr[i]>0x7E)?2:1) seek++;
for (j=0,seek=1;seek<=range;)
{
if (inStr[i])
if (inStr[i]<0x20||inStr[i]>0x7E)
{
outStr[j]=inStr[i];
outStr[j+1]=inStr[i+1];
i+=2,j+=2;
}
else
{
outStr[j++]=inStr[i++];
}
else return 0;
seek++;
}
outStr[j]=0;
return 1;
}
// 文字数=Len(元文字列バッファ)
int Len(char* inStr)
{
int i,len;
for (i=0,len=0;inStr[i];i+=(inStr[i]<0x20||inStr[i]>0x7E)?2:1) len++;
return len;
}
int main()
{
char str[]="パソコンでABC",buf[20];
printf("%s の文字数は、%d 文字です\n",str,Len(str));
if (mid(str,3,6,buf,20))
printf("%s \n",buf);
else
printf("サイズが合いません\n");
if (mid(str,3,6,buf,5))
printf("%s \n",buf);
else
printf("サイズが合いません\n");
if (mid(str,2,8,buf,20))
printf("%s \n",buf);
else
printf("サイズが合いません\n");
return 0;
}
のようにコード体系に合わせると良いかと思います。
No.1
- 回答日時:
> C言語のソースは基本的にSJIS書き、コンパイルすると解釈してよいですか?
処理系によります、といいたいところですが、確実に特定の文字コードにするためには、拡張表記を用いて文字コードを直接記述する必要があります。
> char moji[] = "パソコンでABC";
ではなく、
char moji[] = "\x83\x70\x83\x5c\x83\x52\83\x93\x82\xc5ABC";
とします。
> len,mid関数
Visual Basicの同名関数でしょうか?
だとすると、いったんUnicodeに変換する必要があります。処理系を特定しないのであれば、自分でSJIS ←→ Unicodeの変換関数を作る必要があります。
いったんUnicodeに変換してしまえば、あとは多バイト文字を意識しなくてもよいはずです。出力時に、再度SJISに戻す必要があるでしょうが。
Unicodeに変換せず、多バイト文字のまま扱うのであれば、自分でSJISの1バイト目、2バイト目を判別して、処理するしかありません。
ただし、処理系を特定できるのであれば、この限りではありません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# C言語 3 2022/10/04 15:07
- Java Javaの問題なのですが、「3文字以上の英数字文字列を入力し、文字列の中に文字(9)が出てくるまでの 1 2023/06/06 18:55
- SQL Server [SQLServer] テーブル名からカラム名を取得する 1 2022/08/23 21:20
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# 【C言語】全角文字の配列を、全角のまま1文字ずつ出力する方法 4 2023/05/09 15:08
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringのFindで文字列検索を行...
-
C言語、単語ごとに改行したい
-
文字列中に含まれる文字の個数...
-
Cで「大文字、小文字の判定」は...
-
charと%c , %s の関係について
-
sscanfとscanfの違いがよくわか...
-
文字列の途中に「0」がある場...
-
C言語のステップ数をカウントす...
-
エディットボックスに入力され...
-
[Java]文字列分割
-
ある文字列で2回目3回目に出現...
-
日本語の変換の問題
-
教えていただけませんか?C言語...
-
CStringについて
-
itoaわかりません
-
C言語の問題 キーボードから1 ...
-
スペースで区切って数字を入力
-
getchar分を用いて入力された文...
-
文の意味
-
C言語 空白の行(改行のみ)が...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CStringのFindで文字列検索を行...
-
sscanfとscanfの違いがよくわか...
-
charと%c , %s の関係について
-
fgets関数を使用したときの文字...
-
反転した数値を表示させるやり方
-
fgetsで拾われる改行文字を削除...
-
C言語 空白の行(改行のみ)が...
-
itoaわかりません
-
Cで「大文字、小文字の判定」は...
-
文字列中に含まれる文字の個数...
-
C言語で16進数文字列から16進数...
-
strstrを利用しない文字列検索...
-
小文字のみを数える方法
-
C言語のステップ数をカウントす...
-
C言語でパスワード作成ツール
-
単語数のカウントについて
-
str[j++]の意味
-
fgetsでバッファ残留文字列を無...
-
教えていただけませんか?C言語...
-
エディットボックスに入力され...
おすすめ情報