C言語関係掲示板

過去ログ

No.312.漢字かカタカナか英数字かを判断する方法

[戻る] [ホームページ]

No.1911

char1バイトを、if条件式で漢字かカタカナか英数字かを判断する方法
投稿者---1108(2002/07/02 18:16:20)


まったくの初心者です。
if ((S5.strCMNT_LN2[29]) >= 0x00) 
 S5.strCMNT_LN2[29] = 0x31; 
  else if ((S5.strCMNT_LN2[29]) >= 0xA0)
S5.strCMNT_LN2[29] = 0x32;
else S5.strCMNT_LN2[29] = 0x33;

上のソースは例えばですが、
質問の内容としましては、40バイトの文字列を30バイトの文字列にコピーした場合に
コピーされた側の30バイト目の1バイトで、その文字列が漢字の1バイトなのか
(元データの30バイト目に漢字を入力した場合)、シングルバイトのカタカナなのか、
数字なのか、アルファベットなのかが判断できるでしょうか?
Hexで判断しようとしているのですが、シングルバイトカタカナと漢字の1バイト目の判断がわかりません。
(どうすればいいかが分からないと言った方が正しいのですが)
 よろしくお願いします

No.1912

Re:char1バイトを、if条件式で漢字かカタカナか英数字かを判断する方法
投稿者---かずま(2002/07/02 19:41:15)


> シングルバイトカタカナと漢字の1バイト目の判断がわかりません。

片仮名は 0xA1〜0xDF。漢字の1バイト目は 0x81〜0x9F、0xE0〜0xFC なので区別でき
ます。できないのは、漢字の2バイト目の、0x40〜0x7E、0x80〜0xFC でしょう。
/* type -- s[n] のタイプを返す */
int type(char *s, int n)
{
    int c = s[n] & 0xFF;

    if (n > 0 && c >= 0x40 && c != 0x7F && c <= 0xFC && type(s, n-1)=='1')
        return '2';      /* 40-7E, 80-FC: 漢字第2バイト */
    if (c <= 0x7F) return 'A';  /* 00-7F: ASCII         */
    if (c == 0x80) return 'U';  /* 80   : 未定義        */
    if (c <= 0x9F) return '1';  /* 81-9F: 漢字第1バイト */
    if (c == 0xA0) return 'U';  /* A0   : 未定義        */
    if (c <= 0xDf) return 'K';  /* A1-DF: 片仮名        */
    if (c <= 0xFC) return '1';  /* E0-FC: 漢字第1バイト */
    return 'U';                 /* FD-FF: 未定義        */
}

/* Test Program */
#include <stdio.h>
#include <string.h>

int main()
{
    char buf[1024];

    while (fgets(buf, sizeof buf, stdin) && buf[0] != '.') {
        int n = strlen(buf)/2;
        int t = type(buf, n);
        printf("buf[%d]=%02x: %c\n", n, buf[n]&0xFF, t);
    }
    return 0;
}


No.1920

Re:char1バイトを、if条件式で漢字かカタカナか英数字かを判断する方法
投稿者---かずま(2002/07/03 11:25:38)


先に提示したプログラムは、バグではないのですが、0x40 未満のバイトが現れるまでさかのぼる
ことと、再帰呼び出しを使っていることから、効率が悪いということで、次のように修正します。
#define isFirst(c)     ((unsigned)((c ^ 0x20) - 0xA1) < 60)
#define isSecond(c)    (c >= 0x40 && c != 0x7F && c <= 0xFc)
/* #define isFirst(c)  (c >= 0x81 && c <= 0x9F || c >= 0xE0 && c <= 0xFC) */

int type(char *s, int n)
{
    int i = n, t = 'A';
    unsigned char c;

    while (i > 0 && (c = s[i], isSecond(c)) && (c = s[i-1], isFirst(c)))
        --i;
    do {
        c = s[i];
        if (t == '1') t = '2'; /* 40-7E, 80-FC: 漢字の第2バイト */
        else if (c <= 0x7F) t = 'A';  /* 00-7F: ASCII           */
        else if (c == 0x80) t = 'U';  /* 80   : 未定義          */
        else if (c <= 0x9F) t = '1';  /* 81-9F: 漢字の第1バイト */
        else if (c == 0xA0) t = 'U';  /* A0   : 未定義          */
        else if (c <= 0xDf) t = 'K';  /* A1-DF: 片仮名          */
        else if (c <= 0xFC) t = '1';  /* E0-FC: 漢字の第1バイト */
        else t = 'U';                 /* FD-FF: 未定義          */
    } while (++i <= n);
    return t;
}

/* Test Program */
#include <stdio.h>

int main()
{
    char s[] = "abcあい\xb3\xb4";  /* "abcあいウエ" */
    int i;

    for (i = 0; i < sizeof(s); i++)
        printf("s[%d]=%02x: %c\n", i, s[i] & 0xFF, type(s, i));
    return 0;
}


No.1931

Re:char1バイトを、if条件式で漢字かカタカナか英数字かを判断する方法
投稿者---1108(2002/07/03 18:13:58)


本当にありがとうございました。

プログラム上これで良いのか分かりませんが(美しい?)、
取り敢えず漢字の判断は出来るようになりました。

構造体でのデータを
unsigned char c;
に代入し直して、条件文で判断したところ問題なく動いております。


大変参考になりました。(と言うよりコピーさせていただいたという方が正しい表現ですが...)


No.1921

Re:char1バイトを、if条件式で漢字かカタカナか英数字かを判断する方法
投稿者---1108(2002/07/03 12:11:18)


レス、ありがとうございます。

>if (c <= 0x7F) return 'A'; /* 00-7F: ASCII */
>
> if (c == 0x80) return 'U'; /* 80 : 未定義 */
> if (c <= 0x9F) return '1'; /* 81-9F: 漢字第1バイト */

そうなんですよね!(すいませんえらそうで) 本来なら、漢字の1バイトめはこのif文で引っかかるはず
なんですけど('あ'の場合0x82 , 0xA0なので)、最初の<= 0x7Fで引っかかって'A'がセットされてしまうのです。


if文の左辺がSturct charで指定しているのですが、...
何か他に注意することはあるのでしょうか?

if ((S5.strCMNT_LN2[0]) <= 0x7F)
return 'A';

typedef struct RSP_S5struct
{
char strRCD_TYP[3];
char strPROD_CD[16];
char strUOM[6];
char strORIG_QTY_ORD[10];//PIC 9(9)
char strQTY_SPLY[10];//PIC 9(9)
char strPRC[10];//PIC 9(6).9(2)
char strDISC_PCT[6];//PIC 9(2).9(2)
char strSLS_TAX_PCT[6];//PIC 9(2).9(2)
char strWT[11];//9(5).9(4)
char strVOL[11];//9(5).9(4)
char strORD_CD[11];
char strDLVR_ITEM_LN_NUM[7];
char strDSPCH_OCC[5];
char strCMNT_LN1[31];
char strCMNT_LN2[31];
char strCMNT_LN3[31];
char strQTY_PICK[13];//9(7).9(4)


}RSP_S5;


No.1932

Re:char1バイトを、if条件式で漢字かカタカナか英数字かを判断する方法
投稿者---かずま(2002/07/03 18:16:57)


> if (c <= 0x7F) return 'A'; /* 00-7F: ASCII */
> if (c == 0x80) return 'U'; /* 80 : 未定義 */
> if (c <= 0x9F) return '1'; /* 81-9F: 漢字第1バイト */
> 本来なら、漢字の1バイトめはこのif文で引っかかるはずなんですけど('あ'の場合
> 0x82, 0xA0なので)、最初の<= 0x7Fで引っかかって'A'がセットされてしまうのです。

char が符号付きか符号無しかは処理系定義ですが、私たちが通常使っているコンパイラの
ほとんどが、8ビット符号付きです。だから、-128〜127 の値を持ちます。
0x00〜0x7F は 0〜127 で問題ありませんが、0x80〜0xFF は -128〜-1 と解釈されます。
0x82 は -126 ですから、<= 0x7F に引っかかってしまうのです。

私の最初のプログラムでは、int c = s[n] & 0xFF; とすることで、0x80〜0xFF を 128〜255 に
変換しています。再帰呼び出しを使わないように修正したプログラムでは、unsigned char c;
c = s[i] とすることで、この問題を解決しています。unsigned char は 0〜255 の値を持ちます。


> if ((S5.strCMNT_LN2[0]) <= 0x7F) return 'A';

修正方法はもうお分かりですね。

if ((S5.strCMNT_LN2[0] & 0xFF) <= 0x7F) return 'A';

if ((unsigned char)S5.strCMNT_LN2[0] <= 0x7F) return 'A';

unsigned char c; c = S5.strCMNT_LN2[0]; if (c <= 0x7F) return 'A';

No.1933

Re:char1バイトを、if条件式で漢字かカタカナか英数字かを判断する方法
投稿者---1108(2002/07/03 18:53:47)


>
>修正方法はもうお分かりですね。
>
すばらしい説明ありがとうございました。仕組みの方も理解できました。