5

特定の単語が含まれる行を返す必要がある C++ のプログラムがあります。たとえば、ファイルが次のようになっているとします。

the cow jumped over
the moon with the
green cheese in his mouth

「with」を含む行を印刷する必要があります。プログラムが取得するのは、ファイルの先頭からのオフセットだけです (この場合、"with" はファイルの先頭から 24 文字であるため、24 です)。

オフセットだけで「the moon with the」行全体を印刷するにはどうすればよいですか?

どうもありがとう!

4

3 に答える 3

3

これを行うには、各行を個別に読み取り、読み取り前後のファイル位置を記録します。次に、単語のオフセットがその行の境界内にあるかどうかを確認するだけの簡単なチェックです。

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

std::string LineFromOffset(
    const std::string &filename,
    std::istream::pos_type targetIndex)
{
    std::ifstream input(filename);

    //  Save the start position of the first line. Should be zero of course.
    std::istream::pos_type  lineStartIndex = input.tellg();

    while(false == input.eof())
    {
        std::string   line;

        std::getline(input, line);

        //  Get the end position of the line
        std::istream::pos_type  lineEndIndex = input.tellg();

        //  If the index of the word we're looking for in the bounds of the
        //  line, return it
        if(targetIndex >= lineStartIndex && targetIndex < lineEndIndex)
        {
            return line;
        }

        // The end of this line is the start of the next one. Set it
        lineStartIndex = lineEndIndex;
    }

    //  Need a better way to indicate failure
    return "";
}

void PrintLineTest()
{
    std::string str = LineFromOffset("test.txt", 24);

    std::cout << str;
}
于 2012-06-10T15:21:21.737 に答える
2

適切な解決策は、ファイルを最初から目的の位置まで読み取ることです (@Chet Simpson による回答)。最適化が必要な場合 (たとえば、非常に大きなファイル、中間のどこかに配置、典型的な行がかなり短いなど)、ファイルを逆方向​​に読み取ることができます。ただし、これはバイナリ モードで開かれたファイルでのみ機能します (UNIX ライクなプラットフォームの任意のファイルios_base::binary。Windows ではパラメーターを使用してファイルを開きます)。

アルゴリズムは次のようになります。

  • ファイル内の数バイト戻る
  • 数バイトを読み取る
  • そこに行末があればあとは簡単
  • そうでなければ繰り返す

コード (Windows でテスト済み):

std::string GetSurroundingLine(std::istream& f, std::istream::pos_type start_pos)
{
    std::istream::pos_type prev_pos = start_pos;
    std::istream::pos_type pos;
    char buffer[40]; // typical line length, so typical iteration count is 1
    std::istream::pos_type size = sizeof(buffer);

    // Look for the beginning of the line that includes the given position
    while (true)
    {
        // Move back 40 bytes from prev_pos
        if (prev_pos < size)
            pos = 0;
        else
            pos = prev_pos - size;
        f.seekg(pos);

        // Read 40 bytes
        f.read(buffer, prev_pos - pos);
        if (!f)
            throw;

        // Look for a newline byte, which terminates previous line
        int eol_pos;
        for (eol_pos = sizeof(buffer) - 1; eol_pos >= 0; --eol_pos)
            if (buffer[eol_pos] == '\n')
                break;

        // If found newline or got to beginning of file - done looking
        if (eol_pos >= 0 || pos == (std::istream::pos_type)0)
        {
            pos += eol_pos + 1;
            break;
        }
    }

    // Position the read pointer
    f.seekg(pos);

    // Read the line
    std::string s;
    std::getline(f, s, '\n');

    return s;
}

編集: 行末が でマークされている Windows のようなプラットフォームでは、\r\nバイナリ モードを使用する必要があるため、出力文字列には余分な文字が含まれます\r(ファイルの終わりに行末がない場合を除きます)。 )、捨てることができます。

于 2012-06-10T17:21:31.307 に答える
1

各操作の機能があります

fopen- ファイルを開く

fseek- 目的のオフセットまでファイルをシークします

fread- 必要なバイト数を読み取る

fclose- ファイルを閉じる

于 2012-06-10T12:12:51.667 に答える