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

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

ただいまの
回答率

89.12%

特定の言葉を含んだ文章がメモからbuffer2に入らない。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 887

KZK13

score -8

解決できない問題があります。
buffer2に保存した文章が入りません。

あの後、覚えてという言葉の後で○○は◇◇であるという形式にすることで文章をメモに記憶させることはできました。
その次に覚えさせた文章から特定の言葉が含まれていた場合、その文章を少し改造したものを表示するというプログラムを作ろうとしています。
まず、「覚えて」と入力した後に
例えば、「ジュニーは戦場へ行くという映画は面白い。」、「明日は晴れ。」、「どすこいはお相撲。」と入力してエンターキーを押します。
するとtxtに「ジュニーは戦場へ行くという映画は面白い。」、「明日は晴れ。」、「どすこいはお相撲。」と保存されます。
その後に「どんな映画が好きですか?」と入力すると、メモから if (my_str2(buffer2, "映画")) という条件により「映画」を含んだ文章を読み込み、
「ジュニーは戦場へ行くという映画は面白い。」をbuffer2に入れて「ジュニーは戦場へ行くという映画は面白い。」と返すようにします。

しかし、実際に実行するとbuffer2の方で文章が読み込めていますが、「ジュニーは戦場へ行くという映画は面白い。」という結果は表示されませんでした。
if (my_str2(buffer2, "映画")) という条件により「映画」を含んだ文章を読み込み、表示できると思っていました。しかし、実際は「映画」という言葉をメモから読み込んで一致させただけで、「映画」という言葉を含んだ文章を表示させるための処理が書かれていませんでした。
また、どうやったら太い黒文字で書いたような処理ができるのかの書き方がわかりません。
どうか私が書けるヒントとなるサンプルのプログラムなど頂けないでしょうか。

期待する結果: 「映画」という言葉を含んだ文章である"ジュニーは戦場へ行くという映画は面白い。"が画面に出力されるというのが期待です。

以下は画像です。
「どんな映画が好きですか?」の入力後
「どんな映画が好きですか?」の入力後で実行した後の値

コードです

汚いかもしれませんが、必要最低限の部分のみでコードを編集しました。
短くしたコードです

すいません、kazuma-sさん、編集後のプログラムでもなぜかエラーが起きます。
私のビルドの仕方が悪いのかもしれません。
エラーメッセージが出てしまいます。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • DreamTheater

    2020/07/01 10:56

    質の悪い質問者をブロックする機能がteratailにも必要かもな。。。
    epistemeさんお疲れ様でした。

    キャンセル

  • episteme

    2020/07/01 11:44

    ↑ブロック回避のためアカウント乗り換える輩が続出すんじゃないかな...

    キャンセル

  • 退会済みユーザー

    2020/07/02 00:37

    複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

回答 2

checkベストアンサー

+1

memo.txt

「ジョニーは戦場へ行った」という映画は面白い。
明日は晴れ。
どすこいはお相撲。
映画館はどこも満席。
休日はおうちで映画鑑賞。
#pragma warning(disable: 4996)
#include "DxLib.h"

int readMemo(char **memo, int n)
{
    FILE *fp = fopen("memo.txt", "r");
    if (fp == NULL) return 0;
    int i;
    char buf[256];
    memo[0] = "";
    for (i = 1; i < n && fgets(buf, sizeof buf, fp); i++)
        memo[i] = strdup(buf);
    fclose(fp);
    return i;
}

void drawMemo(char **memo, int n)
{
    int x = 10, y = 420, color = GetColor(0, 255, 0);
    for (int i = 1; i < n; i++) {
        DrawFormatString(x, y, color, "%2d: %s", i, memo[i]);
        y += 30;
    }
}

int findMemo(char **memo, int n, char *str)
{
    if (str[0] != '\0') 
        for (int i = 0; i < n; i++)
            if (strstr(memo[i], str)) return i;
    return 0;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    SetGraphMode(1280, 720, 32);        // ウィンドウの大きさを指定
    ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
    if (DxLib_Init() == -1) return -1;  // DXライブラリの初期化
    SetDrawScreen(DX_SCREEN_BACK);      // 描画先を裏画面にする
    SetFontSize(24);                    // フォントサイズを 24に変更

    char *memo[10];
    int n_memo = readMemo(memo, 10);
    if (n_memo == 0) { DxLib_End(); return 1; }
    int n_show = 0;

    int kih = MakeKeyInput(256, FALSE, FALSE, FALSE); // key input handle
    SetActiveKeyInput(kih);

    char buf[256] = "";

    int input_color = GetColor(255, 255, 0);
    int show_color = GetColor(255, 0, 255);
    int buf_color = GetColor(0, 255, 255);

    while (ProcessMessage() == 0) {
        ClearDrawScreen(); // 画面の初期化

        DrawKeyInputModeString(1200, 0); // 入力モードを描画
        DrawString(10, 30, "入力: ", input_color);
        DrawKeyInputString(80, 30, kih); // 入力途中の文字列を描画

        if (CheckKeyInput(kih) != 0) {   // 入力完了なら
            GetKeyInputString(buf, kih);   // 入力文字列を取得
            n_show = findMemo(memo, n_memo, buf);  // メモを検索
            SetActiveKeyInput(kih);
            SetKeyInputString("", kih);
        }
        DrawFormatString(10, 80, buf_color, "検索文字列: %s", buf);
        DrawFormatString(10, 110, show_color, "検索結果: %s", memo[n_show]);
        drawMemo(memo, n_memo);  // メモを表示

        ScreenFlip(); // 裏画面の内容を表画面に反映させる
    }
    DeleteKeyInput(kih);
    DxLib_End();
    return 0;
}


追記
memo[0] = ""; や or でエラーにならなかったのは、
私のコンパイラが Visual C++ 2017 のものであったからだと思われます。

memo[0] = (char *)""; に変更したのはエラーメッセージに
「error C2440: '=': 'const char [1]' から 'char *' に変換できません。」
とあったからです。キャスト (char *) により強制的に変換させました。

他にコードについての疑問点はありませんか?
完全に理解されましたか?

おまけ

#pragma warning(disable: 4996)
#include <stdio.h>   // fopen, fgets, fclose, printf, puts
#include <string.h>  // strdup, strstr, strchr, strcmp, strlen

#define MEMO_FILE  "memo2.txt"

enum { SEARCH, MEMORY };  // 検索モード、記憶モード

int getline(char *buf, int size, FILE *fp)
{
    if (!fgets(buf, size, fp)) return EOF;
    char *p = strchr(buf, '\n');
    if (p) *p = '\0';
    return strlen(buf);
}

int readMemo(char **memo, int size)
{
    FILE *fp = fopen(MEMO_FILE, "r");
    if (fp == NULL) return 0;
    int i;
    char buf[256];
    memo[0] = (char *)"";
    for (i = 1; i < size && getline(buf, sizeof buf, fp) >= 0; i++)
        memo[i] = strdup(buf);
    fclose(fp);
    return i;
}

int saveMemo(char **memo, int n)
{
    FILE *fp = fopen(MEMO_FILE, "w");
    if (fp == NULL) return 1;
    for (int i = 1; i < n; i++)
        fprintf(fp, "%s\n", memo[i]);
    fclose(fp);
    return 0;
}

void drawMemo(char **memo, int n)
{
    for (int i = 1; i < n; i++)
        printf("%2d: %s\n", i, memo[i]);
}

int addMemo(char **memo, int size, int n, const char *str)
{
    if (n >= size) return 1;
    memo[n++] = strdup(str);
    return 0;
}

int findMemo(char **memo, int n, char *str)
{
    for (int i = 0; i < n; i++)
        if (strstr(memo[i], str)) return i;
    return 0;
}

int main()
{
    char *memo[100];
    memo[0] = (char *)"";
    int n_memo = 1;
    int mode = SEARCH;

    puts("コマンド: 記憶、検索、表示、保存、取得、終了");

    while (1) {
        char buf[256];
        printf("入力: ");
        if (getline(buf, sizeof buf, stdin) < 0) break;
        if (buf[0] == '\0') continue;

        if (!strcmp(buf, "終了")) break;
        else if (!strcmp(buf, "記憶")) mode = MEMORY;
        else if (!strcmp(buf, "検索")) mode = SEARCH;
        else if (!strcmp(buf, "表示")) drawMemo(memo, n_memo);
        else if (!strcmp(buf, "保存")) saveMemo(memo, n_memo);
        else if (!strcmp(buf, "取得")) n_memo = readMemo(memo, 100);
        else if (mode == MEMORY) {
            if (addMemo(memo, 100, n_memo, buf)) puts("  追加できません");
            else n_memo++;
        }
        else {  // mode == SEARCH
            int n_find = findMemo(memo, n_memo, buf);
            if (n_find > 0) printf("  検索結果: %s\n", memo[n_find]);
            else printf("  「%s」は見つかりません\n", buf);
        }
    }
    return 0;
}


追記2
解決済みになってしまいましたが、どのようにして解決したのですか?

「覚えて」のあと、記憶させる文字列を複数入力し、「映画」で検索するコードが
書けたのなら、それを提示してください。

私の回答のコメント欄に、
「これから読ませていただくので疑問はその後に答えさせて頂けないでしょうか。」
と書いたことを実行してください。

おまけのコードで、「入力: 」よりも現在のモードを表示したほうがよいので
次のように変更してください。

-        printf("入力: ");
+        printf(mode == MEMORY ? "記憶: " : "検索: ");

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/01 08:13

    line70~:
    if ( n_show != 0 ) {
    DrawFormatString(10, 110, show_color, "検索結果: %s", memo[n_show]);
    } else {
    DrawFormatString(10, 110, show_color, "申し訳ありません %s とは何ですか?", buf);
    }

    キャンセル

  • 2020/07/04 23:18 編集

    kazuma-sさん、解答の編集でのコードどうもありがとうございます。
    環境を再度整えたらできました。ありがとうございます。

    キャンセル

  • 2020/07/05 02:19

    編集ありがとうございます。
    こちらがコードです。https://pastebin.com/Kjeyvx2v
    kazuma-sさんから頂いたコードを利用させていただいています。

    キャンセル

+1

※ 回答ではありませんし、C実装でもありません。
暇つぶしに書いてみたんで、なにかのタシになれば。

#include <iostream>
#include <fstream>
#include <random>
#include <string>
#include <vector>

/* fileで指定されたテキストファイル内の文字列の中から
   wordを含む文字列を返す。
   複数ある場合、そのうちいずれかを乱数を用いて返す。
   存在しない場合/ファイルオープン失敗の場合、空文字列を返す。
*/
std::string find_word(const std::string& file, const std::string& word) {
  std::string result;
  std::ifstream stream(file);
  if ( stream.is_open() ) {
    std::vector<std::string> lines;
    std::string line;
    // wordを含む文字列の集合をlinesに求める
    while ( std::getline(stream, line) ) {
      if ( line.find(word) != std::string::npos ) {
        lines.push_back(line);
      }
    }
    // linesが空でなければ、そのうちいずれかをデタラメに返す
    if ( !lines.empty() ) {
      std::random_device gen;
      std::uniform_int_distribution<int> dist(0, lines.size()-1);
      result = lines.at(dist(gen));
    }
  }
  return result;
}

int main() {
  std::string word = "映画";
  for ( int i = 0; i < 10; ++i ) {
    std::string result = find_word("d.txt", word);
    if ( !result.empty() ) {
      std::cout << word << " -> " << result << std::endl;
    }
  }
}


d.txt:

ジュニーは戦場へ行くという映画は面白い。
明日は晴れ。
どすこいはお相撲。
映画館はどこも満席。
休日はおうちで映画鑑賞。


実行結果:

映画 -> ジュニーは戦場へ行くという映画は面白い。
映画 -> 休日はおうちで映画鑑賞。
映画 -> ジュニーは戦場へ行くという映画は面白い。
映画 -> 映画館はどこも満席。
映画 -> ジュニーは戦場へ行くという映画は面白い。
映画 -> 映画館はどこも満席。
映画 -> 映画館はどこも満席。
映画 -> 映画館はどこも満席。
映画 -> ジュニーは戦場へ行くという映画は面白い。
映画 -> 休日はおうちで映画鑑賞。

[追記] もっと簡単になるな...

#include <iostream>
#include <fstream>
#include <random>
#include <string>

/* fileで指定されたテキストファイル内の文字列の中から
   wordを含む文字列を返す。
   複数ある場合、そのうちいずれかを乱数を用いて返す。
   存在しない場合/ファイルオープン失敗の場合、空文字列を返す。
*/
std::string find_word(const std::string& file, const std::string& word) {
    std::string result;
    std::ifstream stream(file);
    if (stream.is_open()) {
        std::string line;
        int count = 0;
        std::random_device gen;
        while (std::getline(stream, line)) {
            if (line.find(word) != std::string::npos) {
              ++count;
              if ( std::bernoulli_distribution(1.0/count)(gen) ) result = line;
            }
        }
    }
    return result;
}

int main() {
    std::string word = "映画";
    for (int i = 0; i < 10; ++i) {
        std::string result = find_word("d.txt", word);
        if (!result.empty()) {
            std::cout << word << " -> " << result << std::endl;
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/01 21:53

    時系列からしてバレバレだし、隠そうともしてないからね。

    キャンセル

  • 2020/07/01 22:11

    ネットストーカーは認めるのか、、、(困惑)
    何にしても、もう終わったんで返事はいらないです。

    キャンセル

  • 2020/07/02 07:48

    あの後、徹夜してコードを見直したところ、元のコードをあまり崩すことなく、epistemeさんやkazuma-sのプログラムに近いプログラムが出来ました。DXライブラリは使っていません。
    やっと原因はわかりました。何がいけなかったのかに気が付くまでに長い時間を費やしましたが、自分のコードにおいての問題を解決できてほんと良かったです。

    キャンセル

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

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる