連続した文字列の位置

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
研修生

連続した文字列の位置

#1

投稿記事 by 研修生 » 16年前

getcharで入力した文字列の中に連続した2個以上の連続した空白がある場合1つの空白に置き換えるプログラム
を作っている所ですが・・getcgarで入力した1行の文字列の中の連続した空白の始まりの位置を終わりの位置について
導きだせないのでおしえてください。
s=a○○○aのときs[1]の1が始めの位置で終わりはs[3]の3です。この数字2つを求めたいのですが

char s[1000];
int c, x;


//入力した文字を配列sにいれる
for(int i=0; i<(c = getchar()) != EOF && c != '\n'; ++i){
  s = c;
}

//位置を探す
for(int j=0; j<i; j++){
  if(s[j] == s[j + 1] && s[j] ==' '){
     x = j;
  }
}


まだ全然できていないんですがここからわかりません・・
位置を探すプログラムですが例えばa○○aなら正しく動くんですが
a○○○aやそれ以上の空白があるとxの値が更新されうまくいきません。
多分やり方がおかしいと思います。どのようにすれば導き出せるか教えて下さい。

GPGA

Re:連続した文字列の位置

#2

投稿記事 by GPGA » 16年前

前のプログラムのときから気になっていますが、for文のループ継続条件の
i<(c = getchar()) != EOF
の意味を、きちんと理解していますか?

1, c = getchar()を実行する
2, i < c を実行する。この結果を仮にxとする
3, x != EOF を実行する。
ということをやっているのですよ。

以下、位置を求めるプログラム。
最終目的の空白を詰めるのに役立つかどうかは別。
#include <stdio.h>
#include <string.h>

int main()
{
	const char* s = "a   a b    b c";
	const int len = strlen(s);
	int cnt = 0;
	for (int i = 0; i < len; ++i) {
		if (s == ' ') {
			if (cnt == 0) {
				cnt = i;
				printf("空白開始ポイント:%d\n", cnt);
			} else {
				++cnt;
			}
		} else {
			if (cnt != 0) {
				printf("空白終了ポイント:%d\n", cnt);
			}
			cnt = 0;
		}
	}
}
 

Mist

Re:連続した文字列の位置

#3

投稿記事 by Mist » 16年前

私の会社の新人研修と同じ問題でびっくり。

> 連続した2個以上の連続した空白がある場合1つの空白に置き換える

この仕様を満たせばいのであればこんなめんどくさいことはしないです。
「//入力した文字を配列sにいれる」の部分で「今読んだ文字が空白の場合、ひとつ前の文字が空白だったら配列に入れない」とすればいいだけです。

研修生

Re:連続した文字列の位置

#4

投稿記事 by 研修生 » 16年前

そんなやり方もあったんですね。それでちょっとくんでみたら
int main()
{
   int i,c;
   char s[1000];
   for(i = 0; i < (c= getchar()) != EOF && c!= '\n'; ++i){
     if(c == ' ' && s == ' '){
        ;
      }
   
      else{
        s = c;
      }

  }
 
  printf("%s", s");
  return 0;
}


これうまくいかないんですがどこかおかしいでしょうか?
デバッグでみればわかるかもなのですが超絶ド素人の為ステップインしていくと
for(i = 0; i < (c= getchar()) != EOF && c!= '\n'; ++i){
のところで下記画像のようなのがでてきてしまいます。
開発環境はVisualC++ 6.0です。

研修生

Re:連続した文字列の位置

#5

投稿記事 by 研修生 » 16年前

これのせいで中身が上手く見れません・・

御津凪

Re:連続した文字列の位置

#6

投稿記事 by 御津凪 » 16年前

おそらく、ステップインで getchar() の中に入っていませんか?
(ソースデータが見つからないのでこのようなダイアログが出ます)
ステップオーバーで進めると、関数の中には入らないようになります。

研修生

Re:連続した文字列の位置

#7

投稿記事 by 研修生 » 16年前

デバッグはできました・・ ありがとうございます。
見るとa○○aを入力すると
i=2のときにifに入ってませんね・・
値は一致してるのになんでだろ・・

Mist

Re:連続した文字列の位置

#8

投稿記事 by Mist » 16年前

> s

うん、何となくこの失敗するような気がしてました。
iは0から始まるからi=0のときs[-1]を参照することになります。
範囲外アクセスです。

ヒント:最初の一文字目が「空白が連続した場合」という条件にヒットすることはありえるでしょうか。

Mist

Re:連続した文字列の位置

#9

投稿記事 by Mist » 16年前

あと、GPGAさんの指摘をもう一度よく読みなおして。

初級者

Re:連続した文字列の位置

#10

投稿記事 by 初級者 » 16年前

こんな感じ?

#include <stdio.h>

enum { NON_BLANK, BLANK, BLANKS };

int main(void)
{
    int c, mode = NON_BLANK;

    while ((c = getchar()) != EOF) {
        if (c != ' ') {
            switch (mode) {
            case BLANK: case BLANKS:
                putchar(' ');
                /* fall thru */
            case NON_BLANK:
                putchar(c);
                mode = NON_BLANK;
                break;
            }
        }
        else {
            switch (mode) {
            case NON_BLANK:
                mode = BLANK;
                break;
            case BLANK: case BLANKS:
                mode = BLANKS;
                break;
            }
        }
    }
    return 0;
}

研修生

Re:連続した文字列の位置

#11

投稿記事 by 研修生 » 16年前

for(i = 0; i < (c = (getchar() != EOF)) && c != '\n'; i++)
にしろってことかな・・ なんかおかしいのはわかったきがする・・

御津凪

Re:連続した文字列の位置

#12

投稿記事 by 御津凪 » 16年前

> for(i = 0; i < (c = (getchar() != EOF)) && c != '\n'; i++)
これでは、
"getchar() != EOF" で比較した結果(真偽値)を c に代入し、
それ( c )と i の比較をする、
という処理順序になります。
これだと c に入力した文字が入りませんし、正しくループされません。
for(i = 0; i < 1000 && (c = getchar()) != EOF && c != '\n'; i++)
が、正しいかと思います。

研修生

Re:連続した文字列の位置

#13

投稿記事 by 研修生 » 16年前

初級者さんの提示されたプログラムだとちゃんとできました。ありがとうございました。
自分が今までやってきた方法でもやってみようとおもいます。

研修生

Re:連続した文字列の位置

#14

投稿記事 by 研修生 » 16年前

そういうことか・・
確かにcに文字が入らないですね

初級者

Re:連続した文字列の位置

#15

投稿記事 by 初級者 » 16年前

あのソースはどういう考え方によって書いてあるのかを、よく吟味してください。

「動いた~」だけではダメですよ。

研修生

Re:連続した文字列の位置

#16

投稿記事 by 研修生 » 16年前

それなんですよ。じっくりデバッグで辿っていくと正しいプログラムだというのはわかります。
しかしこれが自分で思いつけるか?といったら少し厳しい気がします。
どういう発想で作ったのか理解していくのが大事なのかな

初級者

Re:連続した文字列の位置

#17

投稿記事 by 初級者 » 16年前

【考え方】
今、自分がどういう状態にいるか(モード)の概念を導入します。

モードには次の3種類があります。
1)非空白モード(NON_BLANK、初期値)
2)1文字空白モード(BLANK)
3)連続空白モード(BLANKS)

各々のモードに対して、入力した1文字が非空白か空白かが対応します。
入力文字とモードの組合せは、下表の6とおりあります。
あのソースは、下表をそのままコード化しただけです。


+-----------+-----------+----------------+----------------+
|    モード |   非空白  |   1文字空白   |    連続空白    |
|           | NON_BLANK |     BLANK      |     BLANKS     |
|入力       |           |                |                |
+-----------+-----------+----------------+----------------+
|           | そのまま  | 空白&そのまま | 空白&そのまま |
|   非空白  | 出力して  | 出力して       | 出力して       |
|           | NON_BLANK | NON_BLANK      | NON_BLANK      |
|           | モードへ  | モードへ       | モードへ       |
+-----------+-----------+----------------+----------------+
|           | 何も      | 何も           | 何も           |
|    空白   | 出力せず  | 出力せず       | 出力せず       |
|           | BLANK     | BLANKS         | BLANKS         |
|           | モードへ  | モードへ       | モードへ       |
+-----------+-----------+----------------+----------------+

閉鎖

“C言語何でも質問掲示板” へ戻る