C言語関係掲示板

過去ログ

No.1085 文字列をアルファベットの次の文字に変更(ただしz,Zはa,Aへ)

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

☆文字列☆
投稿者---愛流(2004/05/25 22:44:48)


文字コードを表示するプログラムを作りました。
#include<stdio.h>

int main(void)
{
char input; /*変数inputをchar型として宣言*/

printf("文字を入れてください:");
scanf("%c", &input); /*文字の入力*/

printf("文字:%c整数:%3d 16進数:%02X\n",input,input,input);
/*inputを%c(文字)、%3d(整数)、%02X(16進数)の3つの形で表示*/

if((input>='A')&&(input<='Z')){
printf("大文字です\n");
}else if((input>=97)&&(input<=0x7a)){
printf("小文字です\n");
}else{
printf("記号です\n");
}

return(0);
}


あと、アルファベットの大文字小文字変換はこう作りました。
#include<stdio.h>

#define MAXLEN 10

int main(void)
{
char input,output;

printf("c="); scanf("%c", &input);

if((input>='a')&&(input<='z')){
output=input-'a'+'A';
}else if((input>='A')&&(input<='Z')){
output=input-'A'+'a';
}

printf("input=%c(%02X),output=%c(%02X)\n",
input,input,output,output);

return(0);
}

それで、
「文字列を入力してアルファベットの次の文字に変更(ただしz,Zはa,Aへ)して出力するプログラム」(例:This→Uijt)
を作ってみようと思ったんですけどなかなかできないんですよ。作れる人いますか??



No.14239

Re:☆文字列☆
投稿者---ぽこ(2004/05/25 23:09:47)


>「文字列を入力してアルファベットの次の文字に変更(ただしz,Zはa,Aへ)して出力するプログラム」(例:This→Uijt)
>を作ってみようと思ったんですけどなかなかできないんですよ。作れる人いますか??

どの辺が分からないのでしょうか?



No.14245

Re:☆文字列☆
投稿者---ぽこ(2004/05/25 23:38:58)


他の方がソースを載せているんで、私も^^;
incalph()で変換を行っています。

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>

void incalph(char * str);

int _tmain(int argc, _TCHAR* argv[])
{
    printf("before:%s\n", argv[1]);
    incalph(argv[1]);
    printf("after :%s\n", argv[1]);
    return 0;
}

void incalph(char * str)
{
    size_t i;
    size_t len = strlen(str);

    for(i = 0; i < len; ++i) {
        if(isupper(str[i])) {
            str[i] = ((str[i] - 'A' + 1) % 26) + 'A';
        } else if(islower(str[i])) {
            str[i] = ((str[i] - 'a' + 1) % 26) + 'a';
        }
    }

    return ;
}



No.14240

Re:☆文字列☆
投稿者---RAPT(2004/05/25 23:13:09)


作れる人いますか??
はい、います。

Windows2000sp4/VC++6.0sp6/Console-App

#include <stdio.h>  /* BUFSIZ, printf, fgets */
#include <string.h> /* strlen */
#include <ctype.h>  /* isalpha, toupper */

int main(void)
{
  char buff[BUFSIZ] = {0};
  size_t i, length;

  printf("文字列を %d バイトまで入れてください:", BUFSIZ);
  fgets(buff, BUFSIZ, stdin);
  length = strlen(buff);

  // 終端文字が改行文字だったら削る

  if(length > 0 && buff[length - 1] == '\n'){
    buff[length - 1] = '\0';
    length--;
  }

  printf("変換前の文字列=[%s]\n", buff);
  for(i = 0; i < length; i++){
    // アルファベット文字か?

    if(isalpha(buff[i])){
      // 大文字にした時 'Z' か? …'z' または 'Z' のとき真

      if(toupper(buff[i]) == 'Z'){
        // 'Z' - 25 == 'A' , 'z' - 25 == 'a' とする

        buff[i] -= 25;
      }else{
        buff[i]++;
      }
    }
  }
  printf("変換後の文字列=[%s]\n", buff);

  return 0;
}



No.14241

Re:☆文字列☆
投稿者---monkey(2004/05/25 23:13:19)


>「文字列を入力してアルファベットの次の文字に変更(ただしz,Zはa,Aへ)して出力するプログラム」(例:This→Uijt)
>を作ってみようと思ったんですけどなかなかできないんですよ。作れる人いますか??

キャラクタセットがASCIIならば,文字コードに1足せば次の文字になる.
文字列は文字コードの配列として扱うことができる.
よって,素朴に考えて次のような方法でできるんでない?

文字列の先頭から末尾まで一文字ずつ参照するループ
{
 もし,'z'なら'a'に変更する
 そうでなく,'Z'なら'z'に変更する
 そうでなければ1足す
}


No.14250

Re:☆文字列☆
投稿者---monkey(2004/05/26 09:09:34)


他の方がコードを載せられたので,ワタシも^^;
#include <stdio.h>
#include <ctype.h>

void transform( char* s )
{
    char* p;
    for( p = s; *p != '\0'; ++p )
    {
        if( isalpha( *p ) )
        {
            if( *p == 'z' )
                *p = 'a';
            else if( *p == 'Z' )
                *p = 'A';
            else
                ++*p;
        }
    }
}

int main( int argc, char* argv[] )
{
    if( argc > 1 )
    {
        printf( "original    \"%s\"\n", argv[ 1 ] );
        transform( argv[ 1 ] );
        printf( "transformed \"%s\"\n", argv[ 1 ] );
    }
    return 0;
}



No.14252

Re:☆文字列☆
投稿者---ぽこ(2004/05/26 09:36:42)



>    for( p = s; *p != '\0'; ++p )
>    {
        ・・・
>    }


#うーん、きれいなFor文だ。
#というか、これが常識的なループの回し方なんですよね。。
#もっとセンス磨かないと駄目ですね。>私


No.14262

Re:☆文字列☆
投稿者---かずま(2004/05/26 13:22:53)


> 文字コードを表示するプログラムを作りました。

でも、その投稿の仕方が間違っていると思いませんか?

   【掲示板ご利用上の注意】
   ・ソースを添付する際には「HTML変換ツール」で字下げしてください。  

#include <stdio.h>

#define t8(c) t7(c),t7(c+128)
#define t7(c) t6(c),t6(c+64)
#define t6(c) t5(c),t5(c+32)
#define t5(c) t4(c),t4(c+16)
#define t4(c) t3(c),t3(c+8)
#define t3(c) t2(c),t2(c+4)
#define t2(c) t1(c),t1(c+2)
#define t1(c) t0(c),t0(c+1)
#define t0(c) (c=='z'?'a':c=='Z'?'A':(c|0x20u)-'a'<25?c+1:c)

char table[] = { t8(0) };

int main(void)
{
    int c;

    while ((c = getchar()) != EOF)
        putchar(table[c]);
    return 0;
}



No.14263

Re:☆文字列☆
投稿者---あかま(2004/05/26 15:34:51)


かずまさんのプログラムに質問です。
一連の#defineでchar型のハッシュテーブルを作っているのはなんとなく分かるのですが、

(c|0x20u)

このorは何をしているのでしょうか?
0x20から印字可能文字ですし、プログラムからしてアルファベットかどうか見分けていると思うのですが、
なぜこれでOK?という気持ちです。


また、展開されたtable[]は次の様になると思うのですが、

char table[] = {(0=='z'?'a':0=='Z'?'A':(0|0x20u)-'a'<25?0+1:0),(1=='z'?'a':1=='Z'?'A':(1|0x20u)-'a'<25?1+1:1),…}

char型の配列に式(式ですよね?)を入れてもコンパイルが通るのはなぜなのでしょうか?
最適化すると定数が残るのは分かるのですが、オプションで最適化を無しにしてもコンパイルが通ります。
(最適化うんぬんではなく文法として合っているからコンパイルが通るのかな???)
なにやら狐につままれているようなコードです。



No.14265

Re:☆文字列☆
投稿者---ともじ(2004/05/26 16:52:41)


すごいプログラムですよね。目が点になりました。

> (c|0x20u)
> このorは何をしているのでしょうか?

'A'〜'Z'を'a'〜'z'に変換しているんですね。
|0x20u だと 'a'〜'z'はそのままで、'A'〜'Z'だけ変換できますね。
これ-'a'が、25未満だったら +1 する、つまり、'A'〜'Y'と'a'〜'y'は+1で、それ以外はそのまま。

> char型の配列に式(式ですよね?)を入れてもコンパイルが通るのはなぜなのでしょうか?

演算の結果が入っているんですね。展開すると、
 :
table[65]:66
table[66]:67
 :
table[89]:90
table[90]:65
table[91]:91
 :
table[97]:98
table[98]:99
 :
table[121]:122
table[122]:97
 :


#出かける用があったのですが、見とれてしまいました。



No.14266

Re:☆文字列☆
投稿者---かずま(2004/05/26 16:58:07)


> (c|0x20u)
>
> このorは何をしているのでしょうか?

ASCII で c が大文字の場合、演算結果は小文字になります。

0x20u は unsigned ですから、(c|0x20u)-'a' も unsigned で、
それが 25 より小さければ、isalpha(c) と同じ結果になります。


> char型の配列に式(式ですよね?)を入れてもコンパイルが通るのはなぜなのでしょうか?

定数式だからです。定数だけからなる式はコンパイル時に計算され単なる値に
なります。最適化は関係ありません。


> なにやら狐につままれているようなコードです。

普通は次のように書くでしょう。

#include <stdio.h>

char table[] = {
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
     64,'B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
    'Q','R','S','T','U','V','W','X','Y','Z','A', 91, 92, 93, 94, 95,
     96,'b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
    'q','r','s','t','u','v','w','x','y','z','a',123,124,125,126,127,
    128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
    160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
    176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
    192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
    208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
    224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
    240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
};

void conv(char *s)
{
    unsigned char *p = (unsigned char *)s;

    do {
        *p = table[*p];
    } while (*p++);
}

int main(void)
{
    char buf[1024];

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



No.14268

Re:☆文字列☆
投稿者---かずま(2004/05/26 17:44:15)


> 0x20u は unsigned ですから、(c|0x20u)-'a' も unsigned で、
> それが 25 より小さければ、isalpha(c) と同じ結果になります。

訂正です。
26 より小さければ isalpha と同じ結果になりますが、
25 ですから、'z' と 'Z' は入りません。

それから、t0(c) は次のようにも書けます。

#define t0(c) ((c|0x20)=='z'?c-25:(c|0x20u)-'a'<25?c+1:c)

等値比較の場合、unsigned である必要はありません。



No.14267

Re:☆文字列☆
投稿者---ぽこ(2004/05/26 17:02:01)


>(c|0x20u)

>このorは何をしているのでしょうか?
>0x20から印字可能文字ですし、プログラムからしてアルファベットかどう
>か見分けていると思うのですが、
>なぜこれでOK?という気持ちです。

'A' <= c < 'Z' の時 'a' < (c|0x20u) < 'z'になります。
'a' <= c < 'z' の時 'a' < (c|0x20u) < 'z'になります。
ゆえに、cがアルファベットの時、
0 <= (c|0x20u) - 'a' < 25 になります。
また、"0x20"ではなくて"0x20u"としていることで、符号なしの整数演算として扱われるため、(c|0x20u) - 'a' < 0 となるcはないことになります。

つまり上記の式でcがアルファベットのときのみ、1を加算することになります。

> char型の配列に式(式ですよね?)を入れてもコンパイルが通るのはなぜなのでしょうか?

定数式はコンパイル時に評価されるんじゃないのでしょうか?

#奥が深い。。



No.14269

Re:☆文字列☆
投稿者---あかま(2004/05/26 19:34:00)


お三方解説ありがとうございました。

0x20とorをとる事で小文字に変換
unsignedにすることにより(c|0x20)-'a'が0未満かどうかの比較がいらなくなる(明らかに26より大きい数が返る)のですね。

そして定数だけからなる式はコンパイル時に計算される。

理解しました。