
main関数で定義した文字列
"<pro><name>chad smith</name><id>1234</id><live>America</live></pro>"
があり第一パラメータで検索したいタグを入力すると
その中身を表示するプログラムを作成したいと思います。
>>プログラム名 id
1234
>>プログラム名 name
chad smith
>>プログラム名 pro
<name>chad smith</name><id>1234</id><live>America</live>
のようになります。
自分なりに作成したのが以下の通りです。
#include<stdio.h>
#include<string.h>
#define BUF 256
int main(int argc ,char *argv[])
{
char str1[]="<pro><name>chad smith</name><id>1234</id><live>America</live></pro>";
char *p1, *p2;
int length;
if(argc != 2)
{
fprintf(stderr,"\nUsage :プログラム名 検索したいタグ名\n");
return 1;
}
p1 = strstr(str1, argv[1]);
if(p1==NULL)
{
fprintf(stderr,"\n検索したタグは見つかりませんでした。\n");
return 1;
}
length =strlen(argv[1]);
p2 = strstr(p1 + length, argv[1]);
fprintf(stdout,"\n%.*s\n", (p2-2) - (p1+length+1), p1+length+1);
return 0;
}
一応自分の期待通りに実行されますが
あまり自分の中では良いプログラミングではないような気がします。
後半の部分の(p2-2) - (p1+length+1), p1+length+1あたりがわかりづらいと思います。
もっと良い方法がありましたらよろしくお願いします。
No.5ベストアンサー
- 回答日時:
タグ検索を行う際、基本的な部分に問題がある。
タグの開始は
「<」+「指定の文字」+「>」
でなければならない。
タグの終了は
「</」+「指定の文字」+「>」
でなければならない。
少なくとも、開始時は「<」「>」を、終了時は「</」「>」を含めて検索しないといけない。
元の文字列が
char str1[]="<pro><name>chad smith</name><pr>no idia</pr><id>1234</id><live>America</live></pro>";
であった場合を考えてみよう。
現状のままでは
>>プログラム名 id
や
>>プログラム名 pr
の実行結果が以下のように「予想外の結果」になるでしょう。
>>プログラム名 id
a</pr
>>プログラム名 pr
><name>chad smith</name
この辺りを考慮して書き直すと
#include<stdio.h>
#include<string.h>
#define BUF 256
int main(int argc ,char *argv[])
{
char start_str[BUF];
char end_str[BUF];
char str1[]="<pro><name>chad smith</name><pr>no idia</pr><id>1234</id><live>America</live></pro>";
char *p1, *p2;
int length;
if(argc != 2)
{
fprintf(stderr,"\nUsage :プログラム名 検索したいタグ名\n");
return 1;
}
sprintf(start_str,"<%s>",argv[1]);
sprintf(end_str,"</%s>",argv[1]);
p1 = strstr(str1, start_str);
if(p1==NULL)
{
fprintf(stderr,"\n指定したタグは見つかりませんでした。\n");
return 1;
}
length =strlen(start_str);
p2 = strstr(p1 + length, end_str);
if(p2==NULL)
{
fprintf(stderr,"\n検索したタグは閉じていません。\n");
return 1;
}
fprintf(stdout,"\n%.*s\n", p2 - p1 - length, p1 + length);
return 0;
}
こうすると「意味が判りづらい1とか2の定数」も不要。表示長の計算も「終了タグの開始位置 - 開始タグの開始位置 - 開始タグの長さ」、表示開始点の計算も「開始タグの開始位置 + 開始タグの長さ」となり、スッキリする。
sprintfを用いて簡潔にまとめられるのですね。
そのことにより出力する際に指定もスッキリしていますね。
これで私の不満点が解決しました。
ありがとうございました。
No.4
- 回答日時:
とりあえずソースをより自己説明的にしてみた。
#include<stdio.h>
#include<string.h>
#define BUF 256
#define TAG_START_LEN 1 /* `<' */
#define TAG_END_LEN 1 /* `>' */
#define CLOSE_LEN 1 /* `/' */
int main(int argc ,char *argv[])
{
char str1[]="<pro><name>chad smith</name><id>1234</id><live>America</live></pro>";
char *first, *second;
char *start, *end;
size_t tagname_len, content_len;
if(argc != 2)
{
fprintf(stderr,"\nUsage :プログラム名 検索したいタグ名\n");
return 1;
}
first = strstr(str1, argv[1]);
if(first == NULL)
{
fprintf(stderr,"\n検索したタグは見つかりませんでした。\n");
return 1;
}
tagname_len = strlen(argv[1]);
start = first + tagname_len + TAG_END_LEN;
second = strstr(start, argv[1]);
if(second == NULL)
{
/* 気になるのでエラー処理追加 */
fprintf(stderr,"\n検索したタグは閉じられていません。\n");
return 1;
}
end = second - TAG_START_LEN - CLOSE_LEN;
content_len = end - start;
fprintf(stdout,"\n%.*s\n", content_len, start);
return 0;
}
他の方が突っ込みを入れているとおり、HTMLやXMLから要素を抽出する処理になっていないのですが、とりあえず見やすくするテクニックとして。(なお、二個目がないときのエラー処理を追加しました。)
・変数名は初期化と使用する箇所が近いものを除けば、意味のない名前は避ける。
p1→first
p2→second
(本当はopen_tagとかになるが、現在は文字列を探してるだけなので、あえてこの名前)
・同じ式を何度も書いているのなら、その結果に何らかの意味がある。それを変数にして名前をつける。
p1+length+1 → start
・マジックナンバー(プログラム中に埋め込まれた、リテラル)はマクロ定数化する。そうすると、「何のために」それが使われているのか理解しやすくなる。
+1 → + TAG_END_LEN
-2 → - TAG_START_LEN - CLOSE_LEN
変数・定数名はもうちょっといい名前があるかもしれませんが、この辺は好みもあるので、自分で考えてみてください。
今回は練習ということでHTMLやXMLから要素を抽出する処理ではありませんでした。今回踏まえて今後取り組んで以降と思います。
変数、定数名に関してのご指摘ありがとうございました。
自分だけでなく他人にもわかるプログラムの作成が必要ですよね。
ご丁寧な書き込みありがとうございました。
No.3
- 回答日時:
<id>に対する</id>のような、</何とか>が見つからなかった場合は
どう対応するのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# C言語 プログラミング 4 2022/05/22 11:53
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# プログラミングの問題です。至急教えてください。 /***から***/の部分をプログラミングにしてほし 1 2022/10/13 11:48
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
文字列から空白を取り除きたい...
-
構造体の各メンバにfor文からア...
-
ネットワークにつながっている...
-
半角カナ→16進
-
配列から指定するデータを取り...
-
c言語配列の結合についてです。...
-
charでの計算?
-
テキストデータをそのままバイ...
-
c#でbmp画像の上下反転
-
C言語のポインターで詰まっている
-
fgetc()関数の動作について
-
配列をnビットシフトする
-
PING JPEGファイルのExif規格の...
-
コマンドラインからの入力で
-
日付表示の方法
-
main の引数には const 付けた方が
-
char型からのバイト数取得
-
'const char *' 型は 'char *' ...
-
8進数と16進数で表示するプロ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
文字列から空白を取り除きたい...
-
間接参照のレベルが異なっています
-
C言語のfor文です。 繰り返しの...
-
CStringをwchar_tに変換したい
-
テキストデータをそのままバイ...
-
charからLPTSTRへの変換方法
-
atoi( ) の反対をやりたい
-
charでの計算?
-
配列をnビットシフトする
-
c++ 文字列を入力して、一文字...
-
'const char *' 型は 'char *' ...
-
c言語でユーザ関数を利用して入...
-
干支のプログラム
-
switch文で文字を比較すること...
-
char型からのバイト数取得
-
ネットワークにつながっている...
-
getchar()を int でとる理由...
-
間接操作のレベルとは
-
str系関数を使わずに二つの文字...
おすすめ情報