C言語関係掲示板

過去ログ

No.616.全角半角交じりの文字列を降順にする

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

文字列の降順について
投稿者---配列苦苦(2003/04/21 23:39:45)


只今C言語の復習をしています。問題は入力された値を降順にするという問題です。

半角の入力の場合なら降順はうまくいくのですが、
全角の漢字や仮名になると、うまくいきません、
また半角と全角を入り乱れて入力しても同じくうまくいきません。
文字は2バイトなのでそれを考慮してみましたがだめでした。
どなたかおしえていただければ幸いです。

コンパイラーはbccコンパイラでOSはWindowsXPを使っています。
よろしく御願いします。



#include<stdio.h>

main(){
                 //降順プログラム
int c = 0;                     //ソート用変数
int a = 0;                     //入力された変数の長さ 
int b = 0;                     //ソート用変数
int j = 0;                     //ソート用変数

char box[128];
char zi[128]

memset(box,0x00,sizeof(box)); //入力用
memset(zi,0x00,sizeof(zi));   //ソート時交換用
 gets(box);
a = strlen(box);


if(!( (0x81 <= (box[0] & 0xff) && (box[0] & 0xff) <= 0x9f || \
     0xe0 <= (box[0] & 0xff) && (box[0] & 0xff) <= 0xfc))
  ){
  //ソート
    for(b=0;b<a-1;b++){
        for(c=0;c<a-b-1;c++){
        	j=0;
            if(strcmp(&box[c],&box[c+1]) < 0){

                zi[j] = box[c];
                box[c] = box[c+1];
                box[c+1] = zi[j];
                j++;
             }
        }
    }
  }
if( (0x81 <= (box[0] & 0xff) && (box[0] & 0xff) <= 0x9f || \
     0xe0 <= (box[0] & 0xff) && (box[0] & 0xff) <= 0xfc)
   ){
  //ソート
   for(b=0;b<a-1;b++){
        for(c=0;c<a-b-1;c++){
        	j=0;
            if(strcmp(&box[c,c+1],&box[c+1,c+2]) < 0){

                zi[j] = zi[c];
                box[c] = box[c+1];
                box[c+1] = zi[j];
                j++;
             }
        }
    }
  }
printf("%s\n",box);
   return ;
}


No.5912

Re:文字列の降順について
投稿者---配列苦苦(2003/04/23 01:32:27)


>只今C言語の復習をしています。問題は入力された値を降順にするという問題です。
>
>半角の入力の場合なら降順はうまくいくのですが、
>全角の漢字や仮名になると、うまくいきません、
>また半角と全角を入り乱れて入力しても同じくうまくいきません。
>文字は2バイトなのでそれを考慮してみましたがだめでした。
>どなたかおしえていただければ幸いです。
>
>コンパイラーはbccコンパイラでOSはWindowsXPを使っています。
>よろしく御願いします。
>

長いソースを載せたのがいけなっかたのでしょうか・・・・
なにかアドバイスをください。
よろしく御願いします。


No.5917

Re:文字列の降順について
投稿者---麗@めておら(2003/04/23 12:18:23)


>長いソースを載せたのがいけなっかたのでしょうか・・・・

ソートした結果がどんなものなのか具体的に記述しなかったのが
まずいのかと思います。

>なにかアドバイスをください。
>よろしく御願いします。

C言語ではなく文字コードについて調べられたほうが良いと思います。
googleで
文字コード プログラミング シフト jis
で検索したら良いものが出てくるかもしれません。

No.5926

Re:文字列の降順について
投稿者---配列苦苦(2003/04/24 01:08:05)


>>長いソースを載せたのがいけなっかたのでしょうか・・・・
>
>ソートした結果がどんなものなのか具体的に記述しなかったのが
>まずいのかと思います。
>
>>なにかアドバイスをください。
>>よろしく御願いします。
>
>C言語ではなく文字コードについて調べられたほうが良いと思います。
>googleで
>文字コード プログラミング シフト jis
>で検索したら良いものが出てくるかもしれません。

アドバイスありとうございました。
早速調べましたがまだよくわかりません。
漢字はコードは16進の何から何までと幅が決まって
いるんじゃないんですか?
それとも他になにかあるのでしょうか?

今回、配列で2バイトずつ仮名と漢字用に領域を
とったのですが、それではだめなのでしょうか。
お手数ですがよろしく御願いします。


No.5931

Re:文字列の降順について
投稿者---麗@めておら(2003/04/24 12:05:47)


>漢字はコードは16進の何から何までと幅が決まって
>いるんじゃないんですか?
>それとも他になにかあるのでしょうか?

エスケープシーケンスは考慮されてますか?

私も専門家ではないのでこれ以上のことは知りません。
ゴメンナサイ。

No.5932

Re:文字列の降順について
投稿者---通りすがりA(2003/04/24 14:13:47)


まず、漢字コードはShiftJISとします。
半角の場合は1バイトなので(とします)、そのまま一文字コピーすればいいでしょう。
全角の場合は2バイトコピーすることになるのですが、
降順にする時、元の文字列を後ろからスキャンする場合は
さらに一文字前を調べてそれが全角か半角か調べなければなりません。

#include <stdio.h>

#define BUFSIZE        256

#define ISSJIS(c)    ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c >= 0xff))

void reverse(unsigned char *dest, unsigned char *src);

int main(void)
{
    unsigned char buf[BUFSIZE], buf2[BUFSIZE];
    
    fgets(buf, sizeof(buf), stdin);
    printf("入力は:%s", buf);
    
    reverse(buf2, buf);
    printf("反転:%s\n", buf2);
    
    return 0;
}

void reverse(unsigned char *dest, unsigned char *src)
{
    unsigned char *p, *q;
    
    for (p=src; *p != '\0' && *p != '\n'; p++) {
        if (ISSJIS(*p)) {
            p++;
        }
    }
    p--;
    
    q = dest;
    while (p > src) {
        if (ISSJIS(*(p - 1))) {
            *q++ = *(p - 1);
            *q++ = *p;
            p -= 2;
        } else {
            *q++ = *p--;
        }
    }
    
    if (p == src && !ISSJIS(*p))
        *q++ = *p;
    
    *q = '\0';
}


おかしなとこあったらつっこみ御願いします。


No.5945

Re:文字列の降順について
投稿者---配列苦苦(2003/04/24 23:59:58)


アドバイスありがとうございます。
僕の問題はアスキーコード順に降順するというものでした。
このアドバイスを元に自分の問題についてもう少し考えて
見ようかと思います。

No.5950

Re:文字列の降順について
投稿者---かずま(2003/04/25 05:37:42)


> おかしなとこあったらつっこみ御願いします。

入力: あえいおう
反転: うおいえあ
昇順: あいうえお
降順: おえういあ

入力: 女A
反転: A女 <-- そのプログラムではこうならない
< #define ISSJIS(c)  ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c >= 0xff))
--
> #define ISSJIS(c)  ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc))


No.5969

Re:文字列の降順について
投稿者---通りすがりA(2003/04/25 13:47:41)


>反転: A女 <-- そのプログラムではこうならない

御指摘ありがとうございます。
まったくその通りでした。
srcは前からスキャンするべきでした。

void reverse(unsigned char *dest, unsigned char *src)
{
    unsigned char *p, *q;
    size_t i;
    
    for (p=src; *p != '\0' && *p != '\n'; p++) {
        if (ISSJIS(*p)) {
            p++;
        }
    }
    i = p - src - 1;
    
    q = dest + i;
    p = src;
    
    while (q >= dest) {
        if (ISSJIS(*p)) {
            *q-- = *(p+1);
            *q-- = *p;
            p += 2;
        } else {
            *q-- = *p++;
        }
    }
    
    dest[i + 1] = '\0';
}


>僕の問題はアスキーコード順に降順するというものでした。
意味がよく分かりません。
希望する動作の入力と出力を書くのが一番ですよ。

>ソートした結果がどんなものなのか具体的に記述しなかったのが
>まずいのかと思います。

と、他の方からもありますし。

No.5994

Re:文字列の降順について
投稿者---配列苦苦(2003/04/27 19:16:41)


すいませんでした。質問の内容がおかしかったようですね。
アスキーコード順に降順に並べるというのは、「きょうはいいひだな」
と入力した場合、「いいうきなはひょだ」とあいうえお順に出力される
ことをいいます。
説明不足で申し訳ごさいませんでした。


No.5996

Re:文字列の降順について
投稿者---かずま(2003/04/27 21:33:18)


> アスキーコード順に降順に並べるというのは、「きょうはいいひだな」
> と入力した場合、「いいうきなはひょだ」とあいうえお順に出力される
> ことをいいます。

値が増えていく (上昇していく) のを昇順、
値が減っていく (下降していく) のを降順といいます。
1 2 3 4 5 は昇順です。5 4 3 2 1 は降順です。
ASCIIコードだと、a b c は 0x61 0x62 0x63 ですから、これが昇順です。
Shift JIS の漢字コードだと、「あ い う」が 0x82a0 0x82a2 0x82a4 です
から、これが昇順です。あいうえお順というのは降順ではありません。

また、文字コード順は、辞書順とも異なります。
辞書順だと、「かがく、かかし、きよう、きょう」ですが、
文字コード順だと、「かかし、かがく、きょう、きよう」となります。
か:0x8289、が:0x828A、ょ:0x82E5、よ:0x82E6 だからです。

No.6006

Re:文字列の降順について
投稿者---配列苦苦(2003/04/28 02:44:32)


そうなんですか、すいませんてっきり勘違いして
いたみたいです。
「文字コード順と辞書順というのは違う」というのも
よくわかっていなかったみたいです。
それをふまえても自分のプログラムが文字コード順に
表示されないのがわかりません。
よろしければどこが悪いのかご指摘下さい。
よろしくお願いします。

No.6008

Re:文字列の降順について
投稿者---かずま(2003/04/28 11:08:28)


> それをふまえても自分のプログラムが文字コード順に
> 表示されないのがわかりません。
> よろしければどこが悪いのかご指摘下さい。
>        if(strcmp(&box[c,c+1],&box[c+1,c+2]) < 0){
まず、ここが悪い。
「,」はコンマ演算子ですから、box[c,c+1] は box[c+1] と全く同じです。
おそらく、box[c],box[c+1] の 2バイトと box[c+1],box[c+2] の 2バイト
をまとめて比較しようというつもりかもしれませんが、そうはなりませんし、
たとえ、そうだとしても、その比較に意味がありますか。
また、strcmp が何を比較するものかご存知ですか。

No.6086

Re:文字列の降順について
投稿者---配列苦苦(2003/05/01 02:58:10)


そうだったんですか、てっきり2バイトを比較していると
思っていました。
strcompは対象文字列をアスキーコードで比較すると
思っているんですが・・・。

No.6110

Re:文字列の降順について
投稿者---すがり(2003/05/06 01:08:17)


>strcompは対象文字列をアスキーコードで比較すると
>思っているんですが・・・。

あくまで1バイトずつの比較(=1バイトずつ数字を比較)です。
2バイトで1文字なんてことは一切考慮してくれません。

No.6122

Re:文字列の降順について
投稿者---かずま(2003/05/06 20:09:59)


1バイト文字を 2バイトにして、全部そろえてから sort すればいいでしょう。
昇順になっています。
#include <stdio.h>
#include <stdlib.h>

typedef unsigned short wchar;

#define ISSJIS(c) (((c) ^ 0x20) - 0xA1u < 60)

int mbs2wcs(wchar *w, const char *s)
{
    int i;  unsigned char *p = (unsigned char *)s;

    for (i = 0; *p && *p != '\n'; i++)
        if (ISSJIS(*p))
            w[i] = p[0]<<8 | p[1],  p += 2;
        else
            w[i] = *p++;
    return i;
}

void wcs2mbs(char *s, const wchar *w, int n)
{
    int i;

    for (i = 0; i < n; i++)
        if (w[i] > 0xFF)
            *s++ = w[i]>>8, *s++ = w[i];
        else
            *s++ = w[i];
}

int compare(const void *a, const void *b)
{
    return *(wchar *)a - *(wchar *)b;
}

int main(void)
{
    char buf[256];  wchar wbuf[256];  int n;

    if (fgets(buf, sizeof buf, stdin)) {
        n = mbs2wcs(wbuf, buf);
        qsort(wbuf, n, sizeof *wbuf, compare);
        wcs2mbs(buf, wbuf, n);
        fputs(buf, stdout);
    }
    return 0;
}