• ベストアンサー

文字列

お世話になります。最近文字列を勉強し始めたのですが、文字列になるとてんでダメになってしまいます・・・。お聞きしたいことは2つあります。 1.テキストファイルから英単語を読み込み、それらをアルファベット順に並べ、新たにテキストファイルに書き込むというものです。例えば、 january February march April Apple と読み込んだなら、 Apple April February january march と書き込みたいのです。文字列を配列に格納し、一文字一文字比較していきたいのですが、文字だとどのように比較して順番を変えればよいのでしょうか。数字の比較なら簡単に出来るんですが、文字だとわからなくなってしまいます。 2.これも同じく文字なのですが、テキストファイルから英単語、あるいは英語のフレーズを2つ読み込み、その2つの英語がアナグラムかどうかを判定するものです。 アナグラム→http://d.hatena.ne.jp/keyword/%A5%A2%A5ʥ%B0%A5%E9%A5%E0 例えば、「O, Draconian devil!」と「Leonardo da Vinci!」を読み込んでアナグラムか判定します。ちなみにこれはアナグラムです。これも一文字一文字比較していくと思うのですが、どのように比較すれればよいのかがわかりません。どなたか宜しくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.10

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> int isanagram1(char *str1, char *str2) { int c1[256] = {0}, c2[256] = {0}, i; while(*str1) c1[tolower(*str1 ++)] ++; while(*str2) c2[tolower(*str2 ++)] ++; for(i = 0; i < 256; i ++){ if(isalpha(i) && (c1[i] != c2[i])) return 0; } return 1; } void selectalpha(char *str) { char *c0, *c1; for(c0 = c1 = str; *c0 = tolower(*c1); c1 ++) c0 += (isalpha(*c0) != 0); } void count(char *str, int *c) { char *al = "abcdefghijklmnopqrstuvwxyz", *p; selectalpha(str); while(*str){ if((p = strchr(al, *str ++)) != NULL) c[p - al] ++; } } int isanagram2(char *str1, char *str2) { int c1[26] = {0}, c2[26] = {0}, i; count(str1, c1); count(str2, c2); for(i = 0; i < 26; i ++){ if(c1[i] != c2[i]) return 0; } return 1; } int compc(const void *c1, const void *c2) { return *(char *)c1 - *(char *)c2; } int isanagram3(char *str1, char *str2) { selectalpha(str1); selectalpha(str2); qsort(str1, strlen(str1), sizeof(char), compc); qsort(str2, strlen(str2), sizeof(char), compc); return !strcmp(str1, str2); } int main(void) { char str1[32] = "O, Draconian devil!"; char str2[32] = "Leonardo da Vinci!"; char *result[2] = {"Not Anatram", "Anagram"}; puts(str1); puts(str2); printf("%s\n", result[isanagram1(str1, str2)]); puts(str1); puts(str2); printf("%s\n", result[isanagram2(str1, str2)]); puts(str1); puts(str2); printf("%s\n", result[isanagram3(str1, str2)]); puts(str1); puts(str2); return 0; }

lockwell
質問者

お礼

悩んでいた所が一気に解決されました^^驚きました! 本当に感謝感謝です!ありがとうございます!!

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (9)

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.9

No4, 5 です。 >1つ目のプログラムは出来ました。皆様ありがとうございました! よかったですね、「ソート」は一度習得すれば、あとは応用ですから。 ------------------------------------------------- >No.3 様が以前ご指摘されたように、まずO, Draconian devil!を >昇順に並べ替え、次にLeonardo da Vinci!を同じく昇順に並べ替 >えようとしたのですが・・(投稿者一部修正) ★No4 で記しましたように、この方法では難しいと思います。 >それと、比較はcase-insensitiveなので大文字小文字は区別しません。 ★このことの処理を、「昇順に並べ替え」る前にしないといけませんね。 ------------------------------------------------- >1つの文字列を昇順にする方法が見つかりません。 ★以降に示します(「丸投げ」返球ですが、この方法では本来の目的が叶えられないことを示すため、ソース全文を投稿します)。 #include <stdio.h> #include <string.h> void Sort32( char cWork[] ) {  int i, j, iLen;  char cDummy;  iLen = strlen( cWork );  for( i = 0; i < iLen; i++ ){   for( j = i; j < iLen; j++ ){    if( cWork[i] < cWork[j] ) continue;    cDummy = cWork[i];    cWork[i] = cWork[j];    cWork[j] = cDummy;   }  } } void main() {  char cDevil[32] = "O, Draconian devil!";  char cVinci[32] = "Leonardo da Vinci!";  Sort32( cDevil );  Sort32( cVinci );  printf( "%s\n", cDevil );  printf( "%s\n", cVinci ); } 注:インデントに全角空白を用いています(タブに一括変換して下さい)。 ☆実行すると、 「__!,DOaacdeiilnnorv」 「__!LVaacddeiinnoor」 となります。 (投稿表示のため、半角スペースの代わりに _ を使用) No.3 さんの >並べ替えた文字列を、先頭から1文字ずつ比べていきます。 ★↑難しいどころか、できないですよね。 ★「並べ替え」方式でなく、「26文字種の使用数をカウント」方式を  お勧めします( case-insensitive 対応)。  これですと、例のように文字列長が異なる場合にも使えます。

lockwell
質問者

お礼

文字列をそれぞれ大文字に変換してソートし比較するようなプログラムを作りました。 しかしどちらか一方の文字列に!や,が含まれているとやはり比較してもアナグラムと判断できませんね・・・。 大文字変換の際、配列が!や,に当たると、その配列自体を削除してしまえば、と考えたのですが、その方法がわかりませんでした・・・。 yama5140様がご指摘したように、使用数をカウントする方法で考えたいと思います。本当にありがとうございました!

全文を見る
すると、全ての回答が全文表示されます。
  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.8

> この方法を調べても、2つ以上の文字列を昇順にする方法(私の1つ目の質問のような)は沢山見つかるのですが、 > 1つの文字列を昇順にする方法が見つかりません。 ソートなどのアルゴリズムについて解説している書籍で 勉強なさることを強くおすすめします。

lockwell
質問者

お礼

近いうちに探してみたいと思います。ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.7

> fgetsはファイルを読み込むための関数でしたよね fgets()の第3引数にstdinを指定すれば、標準入力(例:キーボード)からの 入力を受け取れます。

全文を見る
すると、全ての回答が全文表示されます。
  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.6

> 「O, Draconian devil」のようにスペースを入れると、cDevilにO,が、cVinciにDraconianが入ってしまい、セグメンテーションエラーを起こしてしまいました。 > 私のこのやり方はまずかったでしょうか・・・? scnaf()を使うと、スペースを受け取った時点で、例えばcDevilへの 入力を終了したものとみなします。 別の関数、例えばfgets()あたりを使ってみてはいかがでしょうか。 > 例えば単純に、erosとroseを入力してもアナグラムではないと表示されます。 どういったコードでですか? > と、Count26が2つあるからでしょうか。 何をしたときに矛盾と出たのでしょうか? 行なったこととエラーメッセージを正確に教えてください。 なお、どの関数を何回呼び出しても全く問題ありません。

lockwell
質問者

補足

メンテ終わりましたね^^ 初めの質問の所で誤りがありました。 アナグラムかどうか判断するプログラムは、テキストファイルから読み込むのではなく、キーボードから打ち込みます。 それと、比較はcase-insensitiveなので大文字小文字は区別しません。すみませんでした。 1つ目のプログラムは出来ました。皆様ありがとうございました! >asuncion様 キーボードからの入力でscanfを使用したのですが、ご指摘されたようにスペースを使うと正しく入力されないですね。 fgetsはファイルを読み込むための関数でしたよね。これは私の誤りでした。申し訳ありません。 スペースを使っても正しく入力できる関数はありますでしょうか。 eros、roseを試したコードはyama5140様のコードで試させて頂きました。 以下、yama5140様のコードです。 char cDevil[32], cVinci[32];  int iCnt[26] = { 0 }, iCode, i;  for( i = 0; i < 32; i++ ){ // cDevil   if( 0x00 == cDevil[i] ) break; // 文字列終わり   if( 0 == isalpha( cDevil[i] ) ) continue; // 「英文字」判定   iCode = toupper( cDevil[i] ) - 0x41; // 大文字化(◆)   iCnt[ iCode ]++; // 加算  }  for( i = 0; i < 32; i++ ){ // cVinci   if( 0x00 == cVinci[i] ) break;   if( 0 == isalpha( cVinci[i] ) ) continue;   iCode = toupper( cVinci[i] ) - 0x41;   iCnt[ iCode ]--; // 減算  }  for( i = 0; i < 26; i++ ){ // アナグラム判定     if( 0 == iCnt[i] ) continue;   printf( "アナグラムではありません\n" );   break; } asuncion様が以前ご指摘されたように、まずO, Draconian devil!を昇順に並べ替え、次にLeonardo da Vinci!を同じく昇順に並べ替えようとしたのですが、 この方法を調べても、2つ以上の文字列を昇順にする方法(私の1つ目の質問のような)は沢山見つかるのですが、1つの文字列を昇順にする方法が見つかりません。 良い方法はありますでしょうか。

全文を見る
すると、全ての回答が全文表示されます。
  • yama5140
  • ベストアンサー率54% (136/250)
回答No.5

No4 です。 >私は配列をs[256]と1つだけ用意し、 >テキストファイルから読み込んでいるのですが テキストファイルが、 january February march April Apple のようになっていると s[256] には最後の Apple だけが入り、 それ以前の行(レコード)のデータは上書きされてしまいます。 (まさか連結なんかしてないよね?←複雑そう) ★次のように、格納してからでないと・・・。 char cBuf[256], cStore[GYO][256]; while( NULL != fgets( cBuf, 256, fp ) ){  strcpy( cStore[iLine++], cBuf ); // 格納 } ・ (ソート) if( 0 < strcmp( cStore[i], cStore[j] ) ){ (入れ替え(別の配列に待避などで)) } (出力) ☆ソートについては、検索すればいっぱい出てきます。 -------------------------------------------------- ★前回の回答で、関数化できる部分がありました。  ・ Count26( cDevil, iCnt, 1 ); // 関数呼び出し Count26( cVinci, iCnt, -1 );  ・ } void Count26( char cWork[], int iCnt[], int iAdd ) {  int i, iCode;  for( i = 0; i < 32; i++ ){   if( 0x00 == cWork[i] ) break; // 文字列終わり   if( 0 == isalpha( cWork[i] ) ) continue; // 「英文字」判定   iCode = toupper( cWork[i] ) - 0x41; // 大文字化にして   iCnt[ iCode ] += iAdd; // 加減  } }

lockwell
質問者

補足

ご返答ありがとうございます! まず2つ目で質問です。 とりあえずキーボードから文字を入力し試しました。 printf("文字を入力\n"); scanf("%s", cDevil); scanf("%s", cVinci); そしてyama5140さんのおっしゃるようにプログラムを動かしてみたのですが、エラーが起きてしまいました。 「O, Draconian devil」のようにスペースを入れると、cDevilにO,が、cVinciにDraconianが入ってしまい、セグメンテーションエラーを起こしてしまいました。 私のこのやり方はまずかったでしょうか・・・? 2、スペースを入れなくても、どの文字を入力してもアナグラムではないと表示されてしまいます。 例えば単純に、erosとroseを入力してもアナグラムではないと表示されます。 3、関数ですが、矛盾と出てしまいました。 Count26( cDevil, iCnt, 1 ); Count26( cVinci, iCnt, -1 ); と、Count26が2つあるからでしょうか。

全文を見る
すると、全ての回答が全文表示されます。
  • yama5140
  • ベストアンサー率54% (136/250)
回答No.4

★1.は文字列群を昇順にソートし、ソート結果をファイル出力。  ・ソートでは strcmp() を用いる(戻り値、正負で大小判定)。 ---------------------------------------------- ☆質問者様の2.における例文字列、  「O, Draconian devil!」と  「Leonardo da Vinci!」を見ると、     , が一方のみに使われ、文字列長が異なる。   (プロポーショナルでの見かけの文字列長調整?)。  ことから、2つの文字列内をソートし、結果どうしを「比較」する方法では難しいと思います。 ★大文字・小文字を同じとして、26文字種の使用数をカウントし、  双方の使用数が同じかどうかで判定すれば、と思います。  a と A の使用数が iCnt[0] に入ります(◆)。  char cDevil[32], cVinci[32];  int iCnt[26] = { 0 }, iCode, i;  for( i = 0; i < 32; i++ ){ // cDevil   if( 0x00 == cDevil[i] ) break; // 文字列終わり   if( 0 == isalpha( cDevil[i] ) ) continue; // 「英文字」判定   iCode = toupper( cDevil[i] ) - 0x41; // 大文字化(◆)   iCnt[ iCode ]++; // 加算  }  for( i = 0; i < 32; i++ ){ // cVinci   if( 0x00 == cVinci[i] ) break;   if( 0 == isalpha( cVinci[i] ) ) continue;   iCode = toupper( cVinci[i] ) - 0x41;   iCnt[ iCode ]--; // 減算  }  for( i = 0; i < 26; i++ ){ // アナグラム判定     if( 0 == iCnt[i] ) continue;   printf( "アナグラムではありません\n" );   break;  } 注:インデントに全角空白を用いています。

参考URL:
http://e-words.jp/p/r-ascii.html
lockwell
質問者

補足

皆様ご回答本当にありがとうございます! 皆様のいうstrcmp関数を始めて知りました。全然勉強不足です。頑張ります! さて、1つ目ですが、strcmpの使い方を調べ数時間粘ったのですが、躓いてしまいました。 strcmpを使う場合、2つの配列が必要となりますよね。 しかしこの場合、私は配列をs[256]と1つだけ用意し、テキストファイルから読み込んでいるのですが、これだと比較をどうすればいいのかがわかりません。 配列を2つ用意しようとすると、今度はどうテキストファイルから文字を読み込み2つの配列に格納すればいいのかがわからなく躓いてしまいました。 これを解決する方法はありますでしょうか?

全文を見る
すると、全ての回答が全文表示されます。
  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.3

> 「O, Draconian devil!」と「Leonardo da Vinci!」 双方の文字列をそれぞれ昇順または降順に並べ替えます。 並べ替えた文字列を、先頭から1文字ずつ比べていきます。 途中に食い違いがあればアナグラムではありません。 最後まで同じであればアナグラムです。

全文を見る
すると、全ての回答が全文表示されます。
  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.2

文字列の比較の仕方ですね。 strcmp などの関数を使うと大小関係が得られます。 a<b<・・・<z です。アスキーコードだったら a=31 b=32 となっています。 御自分で比較する場合は、文字として比較します。 str1[0] < str2[0] といった具合ですが、文字列の数だけ行う必要が あります。

全文を見る
すると、全ての回答が全文表示されます。
回答No.1

   1、strcmp  2、それぞれの文字数を比較  

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • c言語のポインタ配列

    下記のようなポインタ配列が合った場合、 char *mnthp[4] = { "January", "February", "March", "April" }; Februaryに別の文字列を代入したいのですが、どうすればよいのでしょうか?

  • 文字列操作

    テキストを読みこんで、そのテキストにある単語を抽出するプログラムを作ろうとしています。単語の区切り文字はスペースかタブで、1文字ずつ読みこんで行こうともいます。 しかし、1文字ずつ読みこむ関数fgetcは返値がint型のようです。1文字ずつよみこみながら読みこんだ文字がスペースかタブで無いか見たいのですが、fgetcのint型返り値をchar文字列と比較するにはどうしたら良いでしょうか。

  • ファイルからある文字列の個数を数えたい

    perl5でunixの"wc"や"grep -c"みたいに1つのファイルの中からある文字列の個数を カウントするスクリプトを作ろうとしています。 ファイルは256文字×10万行くらいのテキストで、 検索する文字列は15文字前後×40個(例えば「apple-000001」「lemon_orange」など)です。 どのようなスクリプトを組んだら効率よく各文字列をカウントできるのでしょうか? それよりwcやgrep -cを40回行った方が早いのでしょうか?

    • ベストアンサー
    • Perl
  • テキストから文字列の抽出法

    テキストから文字列を抽出して、比較したいのですが、良いアプリケーションをご存じないでしょうか? 具体的には2つの異なるフォーマットのファイルがあり、それぞれに(同一の文字列かどうか)比較したい文字列は1行ずつソートされた形で含まれています。しかしその同じ行に時刻などの付加情報が含まれているため、行単位で比較することができないのです(行単位で比較できるアプリは知っています)。 文字列とはファイル名ですので、*.* の形で指定して、抽出できればと思うのですが... もしご存知の方がいらっしゃいましたら、教えてください。

  • C言語でアナグラムを求めるプログラム

    C言語初心者で、勉強中です。 今アナグラムを求めるプログラムをC言語で作成しています。 内容はあらかじめある英単語が書いてあるテキストファイルから互いにアナグラムとなっている英単語をすべて求めてそれを出力するというプログラムです。 どこから手をつけていいかわからず悩んでいます。 そこでヒントをいただこうと思って質問しました。 どなたか回答よろしくお願いします。

  • ACCESS 文字列の比較(完全一致)

    いつもお世話になってます。 A = "a" B = "A" IF A = B Then で文字列AとBを比較するとTrueになってしまいますね。でもここではFalseに判定して欲しいのです。 Option Compare Database を Option Compare Binary にすればFalseになるのはわかるのですが、他の箇所の比較に影響が出るのが怖いので、それはしたくありません。 文字列を完全一致で比較する方法があると思うのですが、調べてもわかりませんでした。 知っている方、どなたか教えてください。 ACCESS2000です。 よろしくお願いします。

  • 文字列を配列に…。

    VBはまだ始めたばかりで本当に初歩的なことかもしれませんが分かる方がおられたら是非教えて下さい。 text1.textから取り込んだ文字列を”一文字ずつ”(Dim a(100) as stringで宣言した)配列に格納したいのですがどうしたらいいのでしょうか?? <例>text1.textに"abc"と入力しcommandbuttonを押すとa(0)に"a"がa(1)に"b"がa(2)に"c"が格納されるといったかんじです。 ちなみに今私がしたいのはtext1.textに、ある文字列を入れその文字列を文字コードに変換しそれを一文字分ずつ+1してまたそのコードを文字に直しtext2.textに出力するというものです(ようは簡単な暗号化ですね)。 私はAscとChrコマンドを利用して1文字ずつコードをずらしていこうと思っているのですが、他に良い方法などあるのでしょうか?? 本当に初心者でどのようにしらたよいのか分かりません…。 どなたか分かりやすく教えていただけませんでしょうか?? お願いします。

  • エクセルファイルから指定列の文字を

    エクセルファイルから指定列の文字を、別のテキストファイルの特定の場所へ順番に差し替えたいです。 【例】 A列の文字→元からあるテキストファイルの内容そのままに、●という特定文字へ、住所1、住所2、住所3・・・ というようにエクセルの列に従って、順番に差し替えてくれる方法ってあるでしょうか? コピペだと大変です(涙) よろしくお願いします。

  • evernoteでpdfファイル内の文字列検索につ

    evernoteに取り込んだpdf内の文字列検索についてです。 テキストなどを取り込んだものの場合はそのノートの中の単語がハイライトで表示されますが pdfファイルだと、そのようには表示されません。 その単語が含まれるpdfファイルが検出されるだけなのでしょうか?

  • PowerShellでの文字列置換ができない

    PowerShellで「\」を含む文字列が変換できません。たぶん正規表現とかで問題があると思うのですが・・・ あとテキストファイル内の文字列置換で指定された文字列がある行があった場合、その行を削除するといったことは出来るのでしょうか? 詳しい方いらっしゃいましたらよろしくお願いいたします。 <テキスト> BBBB AAAA NNNN AAAAあああA NNNN AAAA <検索文字列> あああ ※行内に「あああ」をみつけたらその行を丸ごと削除したい・・・