質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

3046閲覧

ブランク(空白)列をタブに置き換えるには?

senbe

総合スコア27

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2015/03/16 21:46

編集2015/03/16 22:03

**問題
「ブランクの列を同じスペーシングを行う最小の数のタブおよびブランク
で置き換えるプログラムentabを書け。」
にとりくんでいます。
下のようにプログラムを作ってみたのですが、上手く動作しません。
間違いをご指摘いただけるとありがたいです!

lang

1#include <stdio.h> 2 3#define MAXLINE 1000 4#define TAB_STOP 8/*タブストップは8文字ごと*/ 5 6int getline(char line[],int maxline); 7void entab(char line[], char en_line[]); 8 9main() 10{ 11 char line[MAXLINE]; 12 char en_line[MAXLINE]; 13 14 while ((getline(line, MAXLINE)) > 0) { 15 entab(line, en_line); 16 printf("%s",en_line); 17 } 18 return 0; 19} 20 21int getline(char s[], int lim) 22{ 23 int c,i; 24 25 for (i = 0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; i++) 26 s[i] = c; 27 if (c == '\n') { 28 s[i] = c; 29 ++i; 30 } 31 s[i] = '\0'; 32 return i; 33} 34 35void entab(char s[],char t[]) { 36 37 int i,j;/* ループカウンタ */ 38 int count;/* ブランクの数を格納する */ 39 int step;/* タブ・ストップまでのブランクの数 */ 40 int ntab;/* 置き換えるタブの数 */ 41 int nblk;/* 置き換えるブランクの数 */ 42 43 i = 0; 44 j = 0; 45 while (s[i] != '\0'){ 46 count = 0; 47 if (s[i] != ' ') { 48 t[j] = s[i]; 49 i++; 50 j++; 51 } 52 else { 53 j = i;/*はじめてブランクが見つかったところ*/ 54 while (s[i] != ' ') {/*ブランク以外の文字にあたるまで*/ 55 ++count; 56 ++i; 57 } 58 step = TAB_STOP - (j % TAB_STOP);/*タブストップまでのブランクの数を求める*/ 59 if (count < step) {/*ブランクの数よりもstepが多い*/ 60 while (0 < count) { 61 t[j] = ' ';/*ブランクをそのままコピーする*/ 62 ++j; 63 --count; 64 } 65 } 66 else 67 if (step <= count) {/*ブランクの数がstep以上*/ 68 ntab = 1 + (count -step)/TAB_STOP; 69 nblk = count - step - ntab; 70 while (0 < ntab) { 71 t[j] = '\t'; 72 ++j; 73 --ntab; 74 } 75 while (0 < nblk) { 76 t[j] = ' '; 77 ++j; 78 --nblk; 79 } 80 } 81 } 82 } 83 t[j] = '\0'; 84} 85 86

例えば
"a****bc"
という文字列が入力されたとき、

s[] 0 1 2 3| 4 5 6 7| 8
a * * * * b c

("*"はブランク、"|"はタブストップの前を表しています。簡単のためプログラムでは8文字です が4文字ごとにおいています。)

a~bまでのブランクの個数を数えて、4つあるとわかる。
タブストップまでの3つを、1つのタブに、
残りの1つを、ブランクにおきかえる。

というふうに考えてかいてみました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

実装例とそのテストの例です。

lang

1#include <stdio.h> 2#include <string.h> 3 4#define MAXLINE (100) // entab 結果の最大文字領域 5#define TAB_STOP (8) // タブストップは8文字ごと 6 7// 印字可能文字な ASCII 文字だけを扱う。 8// TODO: entab の結果が MAXLINE を超える時は MAXLINE より後ろはカットする。 9void entab(char * str, char* entabstr) { 10 int len = strlen(str); 11 int entab_len = 0; // entabstr に転送した文字数 12 int space_len = 0; // entab に転送していない SPACE の数 13 int disp_len = 0; // str[len-1] の文字の 直前のタブストップからの表示位置 (0, 1, ... 7) 14 15 for (int i = 0; i < len; i++) { 16 // entabstr の長さがオーバーしたら、そこで処理を打ち切る。 17 if (entab_len >= MAXLINE - 1) { 18 break; 19 } 20 char c = str[i]; 21 22 if (c == '\t') { 23 disp_len = 0; // タブストップからの表示位置は 0 になる。 24 space_len = 0; // \t の前にあった SPACE は転送しない。 25 entabstr[entab_len] = '\t'; // '\t' を転送する。 26 entab_len++; 27 continue; 28 } 29 30 if (c == ' ') { 31 disp_len++; 32 space_len++; // entabstr には、すぐには転送しない。 33 } else { 34 disp_len++; 35 // 出力していない SPACE があれば、それを entabstr に転送してから c を転送する。 36 if (space_len > 0) { 37 for (int s = 0; s < space_len; s++) { 38 entabstr[entab_len] = ' '; 39 entab_len++; 40 } 41 space_len = 0; 42 } 43 entabstr[entab_len] = c; 44 entab_len++; 45 } 46 47 // 表示位置がタブストップ位置に達した時に、 48 // 出力していない SPACE があれば、'\t' を転送する。 49 if (disp_len % TAB_STOP == 0) { 50 disp_len = 0; // タブストップからの表示位置は 0 になる。 51 if (space_len > 0) { 52 entabstr[entab_len] = '\t'; 53 entab_len++; 54 space_len = 0; 55 } 56 } 57 } 58 entabstr[entab_len] = '\0'; // 文字の終端の nil を書き込む。 59} 60 61char str_max[MAXLINE]; 62char str_max_1[MAXLINE + 1]; 63char * TEST_CASES[] = { 64 /* 0 */ "11223344", "11223344", 65 /* 1 */ "112233 ", "112233\t", 66 /* 2 */ "1122 44", "1122 44", 67 /* 3 */ " 223344", " 223344", 68 /* 4 */ "11 33 ", "11 33\t", 69 70 /* 5 */ "\t", "\t", // SPACE 0 + \t 71 /* 6 */ " \t", "\t", // SPACE 1 + \t 72 /* 7 */ " \t","\t", // SPACE 7 + \t 73 /* 8 */ " \t","\t\t", // SPACE 8 + \t 74 /* 9 */ "11\t", "11\t", 75 76 /* 10 */ "", "", 77 /* 11 */ str_max, str_max, 78 /* 12 */ str_max_1, str_max, 79}; 80void setup_testcases() { 81 for (int i = 0; i < MAXLINE - 1; i++) { 82 str_max[i] = 'x'; 83 } 84 str_max[MAXLINE - 1] = '\0'; 85 86 for (int i = 0; i < MAXLINE; i++) { 87 str_max_1[i] = 'x'; 88 } 89 str_max_1[MAXLINE] = '\0'; 90}; 91 92void test_entab() { 93 94 int len = sizeof(TEST_CASES) / sizeof(char *) / 2; 95 char entabstr[MAXLINE]; 96 97 setup_testcases(); 98 for (int i = 0; i < len; i++) { 99 char * str = TEST_CASES[i * 2]; 100 char * ans = TEST_CASES[i * 2 + 1]; 101 memset(entabstr, '*', MAXLINE); // ダミー値で埋める。 102 entab(str, entabstr); 103 if (strcmp(ans, entabstr) != 0) { 104 printf("#--- Error: %d:\t[%s],\t[%s] != [%s]\n", i, str, ans, entabstr); 105 printf("#--- : \t\t%d,%d\n", (int)strlen(ans), (int)strlen(entabstr)); 106 } 107 } 108} 109 110int main(int atgc, char** argv) { 111 test_entab(); 112 return 0; 113}

投稿2015/03/20 15:02

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

senbe

2015/03/24 05:49

すみません… テストはコンパイルできて、結果が出力されたのですが この実装例は通りませんでした。 Windows機でコマンドプロンプトを使っています。 あと、テストを通したとき、     for (int i = 0; i < len; i++) {     ... のところでエラーとされました。 ので、forループに入る前に変数iを宣言する ように書き換えると、通りました。 int i; ... for (i = 0; ...) { ...
katoy

2015/03/24 15:07

私は Mac で作業してます。 次のように compile, 実行ができていますが。 $ gcc --version Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) Target: x86_64-apple-darwin14.1.0 Thread model: posix $ gcc 2.c $ ./a.out
senbe

2015/03/24 22:35

お手数かけてすみません。 コンパイルできました。
guest

0

まずはテストを書いてみました。
entab 関数は 何も変更しないものを仮実装してあります。
entab 関数が正しくプログラミングできた時には、テストが全て通るとおもいます。

lang

1#include <stdio.h> 2#include <string.h> 3 4#define MAXLINE (100) 5#define TAB_STOP (8) /* タブストップは8文字ごと */ 6 7// 印字可能文字な ASCII 文字だけを扱う。 8// TODO: entab の結果が MAXLINE を超える時は MAXLINE より後ろはカットする。 9void entab(char * str, char* entabstr) { 10 // str をそのまま entabstr に copy するだけの仮実装 11 int len = strlen(str); 12 for (int i = 0; i < len; i++) { 13 char c = str[i]; 14 entabstr[i] = c; 15 } 16 entabstr[len] = '\0'; 17} 18 19char str_max[MAXLINE]; 20char str_max_1[MAXLINE + 1]; 21char * TEST_CASES[] = { 22 /* 0 */ "11223344", "11223344", 23 /* 1 */ "112233 ", "112233\t", 24 /* 2 */ "1122 44", "1122 44", 25 /* 3 */ " 223344", " 223344", 26 /* 4 */ "11 33 ", "11 33\t", 27 28 /* 5 */ "\t", "\t", 29 /* 6 */ " \t", "\t", 30 /* 7 */ "11\t", "11\t", 31 /* 8 */ "", "", 32 /* 9 */ // str_max, str_max, 33 /* 10 */ // str_max_1, str_max, 34}; 35void setup_testcases() { 36 for (int i = 0; i < MAXLINE - 1; i++) { 37 str_max[i] = 'x'; 38 } 39 str_max[MAXLINE - 1] = '\0'; 40 41 for (int i = 0; i < MAXLINE; i++) { 42 str_max_1[i] = 'x'; 43 } 44 str_max_1[MAXLINE] = '\0'; 45}; 46 47void test_entab() { 48 49 int len = sizeof(TEST_CASES) / sizeof(char *) / 2; 50 char entabstr[MAXLINE]; 51 52 setup_testcases(); 53 for (int i = 0; i < len; i++) { 54 char * str = TEST_CASES[i * 2]; 55 char * ans = TEST_CASES[i * 2 + 1]; 56 memset(entabstr, '*', MAXLINE); // ダミー値で埋める。 57 entab(str, entabstr); 58 if (strcmp(ans, entabstr) != 0) { 59 printf("#--- Error: %d:\t%s,\t[%s] != [%s]\n", i, str, ans, entabstr); 60 printf("#--- : \t%d,%d\n", (int)strlen(ans), (int)strlen(entabstr)); 61 } 62 } 63} 64 65int main(int atgc, char** argv) { 66 test_entab(); 67 return 0; 68}

現状では、テストを走らせると次のようになります。

$ gcc entab.c $ ./a.out katoy-no-MacBook-Pro-2:cpp katoy$ ./a.out #--- Error: 1: 112233 , [112233 ] != [112233 ] #--- : 7,8 #--- Error: 4: 11 33 , [11 33 ] != [11 33 ] #--- : 7,8 #--- Error: 6: , [ ] != [ ] #--- : 1,3

TEST_CASES の 1番、4番、6番が正しい entab 結果を返していない事が示されています。
(これ以外は、entab をしても文字列内容に変化が起こらない場合のテストです)

文字列長さが MAXLINE を超える時のテストケースは上ではコメントアウトしてますが、最終的には コメントを外します。

投稿2015/03/17 15:50

編集2015/03/17 22:19
katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

katoy

2015/03/17 22:20

数日後に、このテストをパスする 私の entab() のプログラム例を投稿します、
senbe

2015/03/17 22:30

ありがとうございます!
guest

0

とりあえずで直すと下記のような感じでしょうか。(ちゃんとテストした訳ではないので、各種パターンについてはご確認ください。)

lang

1while (s[i] != ' ') {/*ブランク以外の文字にあたるまで*/ 23while (s[i] == ' ') {/*ブランク以外の文字にあたるまで*/ 4 5ntab = 1 + (count -step)/TAB_STOP; 6nblk = count - step - ntab; 78ntab = (i / TAB_STOP) - (j / TAB_STOP); 9nblk = i - ntab * TAB_STOP;

投稿2015/03/17 04:05

yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問