C言語関係掲示板

過去ログ

No884 S−JISの半角カナを全角カナに変換する関数

[戻る] [ホームページ]
No.219

半角文字列
投稿者---たま(2003/07/09 09:07:54)


初めて投稿します。

S−JISの半角カナを全角カナに変換する関数を作りたいのですが、
何かよい方法はないでしょうか?


No.220

Re:半角文字列
投稿者---もぐりん(2003/07/09 09:42:39)


>初めて投稿します。
>
>S−JISの半角カナを全角カナに変換する関数を作りたいのですが、
>何かよい方法はないでしょうか?

Googleで検索したら、こちらが出ました。
http://hp.vector.co.jp/authors/VA019876/softlib/SoftLib.html
参考になれば。



No.221

Re:半角文字列
投稿者---たま(2003/07/09 13:57:26)


>http://hp.vector.co.jp/authors/VA019876/softlib/SoftLib.html
>参考になれば。

ありがとうございます。
さっそくやってみます。

No.222

Re:半角文字列
投稿者---かずま(2003/07/09 14:08:06)


> S−JISの半角カナを全角カナに変換する関数を作りたいのですが、
> 何かよい方法はないでしょうか?

よい方法は、文字コードをよく調べることです。
#include <stdio.h>

#define KANA \
    "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソ" \
    "タチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜"

#define ISKANJI(c)       (((c) ^ 0x20) - 0xA1u < 60)
#define ISKANA(c)        ((c)-0xA1u < 63)
#define ISDAKU(c)        (((c)&0xFF) == 0xDE)
#define ISHANDAKU(c)     (((c)&0xFF) == 0xDF)
#define MAYBEDAKU(c)     ((c)-0xB6u < 15 || (c)-0xCAu < 5)
#define MAYBEHANDAKU(c)  ((c)-0xCAu < 5)

void hk2zk(const char *han, char *zen)
{
    unsigned char c;

    while (c = *han++)
        if (ISKANJI(c))
            *zen++ = c, *zen++ = *han++;
        else if (!ISKANA(c))
            *zen++ = c;
        else {
            char *p = KANA + (c - 0xA1) * 2;
            *zen++ = p[0], *zen++ = p[1];
            if (MAYBEDAKU(c) && ISDAKU(*han))
                zen[-1]++, han++;
            else if (MAYBEHANDAKU(c) && ISHANDAKU(*han))
                zen[-1] += 2, han++;
        }
    *zen = 0;
}

int main(void)
{
    char buf[256], buf2[512];

    while (fgets(buf, sizeof buf, stdin)) {
        hk2zk(buf, buf2);
        fputs(buf2, stdout);
    }
    return 0;
}



No.404

Re:半角文字列
投稿者---きずく(2003/08/11 09:34:57)


>#define ISKANJI(c) (((c) ^ 0x20) - 0xA1u < 60)
>#define ISKANA(c) ((c)-0xA1u < 63)
>#define ISDAKU(c) (((c)&0xFF) == 0xDE)
>#define ISHANDAKU(c) (((c)&0xFF) == 0xDF)
>#define MAYBEDAKU(c) ((c)-0xB6u < 15 || (c)-0xCAu < 5)
>#define MAYBEHANDAKU(c) ((c)-0xCAu < 5)

すいません。
このデファイン定義の処理はどのようなことをしているのでしょうか。
教えて下さい。

No.405

Re:半角文字列
投稿者---かずま(2003/08/11 11:39:05)


> このデファイン定義の処理はどのようなことをしているのでしょうか。
#define はソースの一部です。ソースを添付する場合は、
【掲示板ご利用上の注意】に従ってください。

次に、Shift-JIS がどんな文字コードか調べましたか?

  00-7F  ASCII と同じ
  80     未定義
  81-9F  2バイト文字の 1バイト目
  A0     未定義
  A1-DF  片仮名
  E0-FC  2バイト文字の 1バイト目
  FD-FF  未定義

#define ISKANJI(c)       (c >= 0x81 && c <= 0x9F || c >=0xE0 && c <= 0xFC)
#define ISKANA(c)        (c >= 0xA1 && c <= 0xDF)

片仮名のうち、濁点は DE、半濁点は DF。
濁音になる可能性のあるのは、カ〜ト、ハ〜ホ、
半濁音になる可能性のあるのは、ハ〜ホなので、

#define ISDAKU(c)        ((c && 0xFF) == 0xDE)
#define ISHANDAKU(c)     ((c && 0xFF) == 0xDF)
#define MAYBEDAKU(c)     (c >= 0xB6 && c <= C4 || c >= 0xCA && c <= 0xCE)
#define MAYBEHANDAKU(c)  (c >= 0xCA && c <= 0xCE)

それとも、
  #define ISKANA(c)  (c >= 0xA1 && c <= 0xDF)
が、
  #define ISKANA(c)  (c - 0xA1u < 63)
と書けるのがなぜだか分からないのでしょうか?


No.406

Re:半角文字列
投稿者---きずく(2003/08/11 12:22:45)


S-JISコードがどのようなコードか、または、ASCIIコードでどこに
位置付けられるのは分かるのですが、

#define ISKANJI(c)       (((c) ^ 0x20) - 0xA1u < 60)
#define ISKANA(c)        ((c)-0xA1u < 63)
#define MAYBEDAKU(c)     ((c)-0xB6u < 15 || (c)-0xCAu < 5)
#define MAYBEHANDAKU(c)  ((c)-0xCAu < 5)


と書けるのがわかりませんでした。


No.407

Re:半角文字列
投稿者---きずく(2003/08/11 12:53:00)


なんどもすみません。

#define ISKANJI(c)       (((c) ^ 0x20) - 0xA1u < 60)
#define ISKANA(c)        ((c)-0xA1u < 63)
#define MAYBEDAKU(c)     ((c)-0xB6u < 15 || (c)-0xCAu < 5)
#define MAYBEHANDAKU(c)  ((c)-0xCAu < 5)


と書けるのが分かりません。

No.408

Re:半角文字列
投稿者---かずま(2003/08/11 14:52:36)


#ISKANA(c)  (c - 0xA1u < 63)

c が 0xA1〜0xDF の 63通りの場合、0xA1 を引くと 0〜62 の値になります。
c が 0xE0以上の場合、0xA1 を引くと 63以上の値になります。
c が 0xA0以下の場合、0xA1 を引くと 負の値になりますが、0xA1u という
unsigned int の値を引いているので、結果も unsigned int になり、負では
なく、正の大きな値になります。
したがって、#ISKANA(c)  (c >= 0xA1 && c <= 0xDF) と等価になります。

#ISKANJI(c)  ((c ^ 0x20) - 0xA1u < 60)

d = c ^ 0x20; とすると、
c が 0x80〜0x9F の場合、d は 0xA0〜0xBF になります。
c が 0xE0〜0xFF の場合、d は 0xC0〜0xDF になります。
すなわち、c が 0x81〜0x9F または 0xE0〜0xFC の場合、
d は 0xA1〜0xDC の 60個の値になります。あとは、ISKANA と同様にして、

#ISKANJI(c)  (c >= 0x81 && c <= 0x9F || c >= 0xE0 && c <= 0xFC)
と等価になります。


No.409

Re:半角文字列
投稿者---きずく(2003/08/11 17:20:05)


丁寧な説明ありがとうございます。

#define ISDAKU(c)        ((c && 0xFF) == 0xDE)
#define ISHANDAKU(c)     ((c && 0xFF) == 0xDF)
#define MAYBEDAKU(c)     (c >= 0xB6 && c <= C4 || c >= 0xCA && c <= 0xCE)

は、

#define ISDAKU(c)        ((c & 0xFF) == 0xDE)
#define ISHANDAKU(c)     ((c & 0xFF) == 0xDF)
#define MAYBEDAKU(c)     (c >= 0xB6 && c <= 0xC4 || c >= 0xCA && c <= 0xCE)


ですよね。

「&&」では論理演算となっておかしくなりませんか。

もう1点教えていただきたいのですが、
「ヴァ、ヴィ、ヴ、ヴェ、ヴォ」を全角にしたく、
デファイン定義を
#define MAYBEDAKU(c)     ((c >= 0xB6 && c <= 0xC4 || c >= 0xCA && c <= 0xCE) || c == 0xB3)


としたのですが、
結果は、
「ェァェィェェェェォ」となってしまいます。

何がおかしくて、どうすればよいのでしょうか。


No.410

Re:半角文字列
投稿者---かずま(2003/08/11 18:58:03)


> 「&&」では論理演算となっておかしくなりませんか。

そうですね。 & です。説明のためにあわてて書いたから間違えました。


> 「ヴァ、ヴィ、ヴ、ヴェ、ヴォ」を全角にしたく、
> デファイン定義を
>
> #define MAYBEDAKU(c)     ((c >= 0xB6 && c <= 0xC4 || c >= 0xCA && c <= 0xCE) || c == 0xB3)
>
>
> としたのですが、
> 結果は、
> 「ェァェィェェェェォ」となってしまいます。

全角(正確には JIS X 0208)では、「カガキギ...ホボポ」の順になっていますが、
「ウ」と「ヴ」は隣り合っていません。そこで、次のようにしてみました。

#define IS_U(c)          (c == 0xB3)

void hk2zk(const char *han, char *zen)
{
    unsigned char c;

    while (c = *han++)
        if (ISKANJI(c))
            *zen++ = c, *zen++ = *han++;
        else if (!ISKANA(c))
            *zen++ = c;
        else {
            char *p = KANA + (c - 0xA1) * 2;
            *zen++ = p[0];
            if (IS_U(c) && ISDAKU(*han))
                *zen++ = "ヴ"[1], han++;
            else if (MAYBEDAKU(c) && ISDAKU(*han))
                *zen++ = p[1]+1, han++;
            else if (MAYBEHANDAKU(c) && ISHANDAKU(*han))
                *zen++ = p[1]+2, han++;
            else
                *zen++ = p[1];
        }
    *zen = 0;
}


No.411

Re:半角文字列
投稿者---きずく(2003/08/11 19:33:12)


かずまさん。
動きました。

もとの文字は分かっているのですから、最初から設定するという
かたちでもいいのでね。

「*zen++ = "ヴ"[1]」
の様な使いかは、初めて見たのですが、
2バイト目を入れているということでよいのでしょうか。

2バイト文字のとき、2バイト目を入れる場合は、このような
書き方になるのでしょうか。



No.412

「*zen++ = "ヴ"[1]」の使い方について
投稿者---きずく(2003/08/12 01:45:59)


「*zen++ = "ヴ"[1]」の使い方が分からず、いろいろと調べてみたのですが、
探し方が下手なのか見つかりませんでした。

これは、どのような処理を行っているのでしょうか。
別の書き方にするとどうなるのでしょうか。
何という記述方法なのでしょうか。

このサイトにも載ってませんでしが。



No.413

Re:「*zen++ = "ヴ"[1]」の使い方について
投稿者---YuO(2003/08/12 02:16:03)


>「*zen++ = "ヴ"[1]」の使い方が分からず、いろいろと調べてみたのですが、
>探し方が下手なのか見つかりませんでした。
>これは、どのような処理を行っているのでしょうか。
>別の書き方にするとどうなるのでしょうか。
>何という記述方法なのでしょうか。

C言語の文法としてみると,特別なことは何もないですから,名前もないです。

文字列リテラルは,charの配列として扱われます。なので,
*zen++ = "ヴ"[1];
は,
static char __literal__vu__[] = "ヴ";
*zen++ = __literal__vu__[1];
に等しいです。


No.414

Re:「*zen++ = "ヴ"[1]」の使い方について
投稿者---とおりすがり(2003/08/12 02:17:26)


>「*zen++ = "ヴ"[1]」の使い方が分からず、いろいろと調べてみたのですが、
>探し方が下手なのか見つかりませんでした。

確かに戸惑う使い方かもしれないけど、基本が出来ていれば、理解できます。
C言語における文字列リテラル(ex. "ヴ")についての理解があればOKかな?
(とりあえず、"ヴ"(文字列リテラル)の型が何かを考えてみましょう)