0


0

段落から3行のテキストを取得する方法

段落から「スニペット」を作成しようとしています。 中央にハイライトされた単語を含む長いテキストの段落があります。 その行の前の単語とその行の後の行を含む行を取得したい。

次の情報があります。

  • テキスト(文字列内)

  • 行は改行文字 `\ n`で終わります

  • 私が強調したいテキストの文字列へのインデックスを持っています

その他のいくつかの基準:

  • 私の言葉が段落の最初の行にある場合、それは表示されるはずです 最初の3行

  • 私の言葉が段落の最後の行にある場合、それは表示されるはずです 最後の3行

  • 変性症例の段落全体を表示する必要があります( 段落には1行または2行しかありません)

これが一例です。

This is the 1st line of CAT text in the paragraph
This is the 2nd line of BIRD text in the paragraph
This is the 3rd line of MOUSE text in the paragraph
This is the 4th line of DOG text in the paragraph
This is the 5th line of RABBIT text in the paragraph

たとえば、インデックスがBIRDを指している場合、1、2、3行目は次のような1つの完全な文字列として表示されます。

This is the 1st line of CAT text in the paragraph
This is the 2nd line of BIRD text in the paragraph
This is the 3rd line of MOUSE text in the paragraph

インデックスがDOGを指している場合、3、4、5行目が次のような1つの完全な文字列として表示されます。

This is the 3rd line of MOUSE text in the paragraph
This is the 4th line of DOG text in the paragraph
This is the 5th line of RABBIT text in the paragraph

etc.

誰もこれに取り組むのを助けたいですか?

4 Answer


3


私の意見では、これは `StringReader`クラスを使用する絶好の機会です。

  1. テキストを1行ずつ読んでください。

  2. 行をある種のバッファ(たとえば、 Queue)に保持し、ドロップします 所定の行数が読み取られた後、不要な行。

  3. 「針」が見つかったら、もう1行(可能であれば)を読んでから、 バッファにあるものを返すだけです。

私の意見では、これには他の提案されたアプローチよりもいくつかの利点があります。

  1. それは `String.Split`を利用しないので、_more_作業をしません 必要以上に-つまり、文字列全体を読み取って分割する文字を探し、部分文字列の配列を作成します。

  2. 実際、文字列全体を必ずしもすべて読み取るわけではありません。 探しているテキストを見つけると、必要なパディング行数を取得するために必要な範囲でのみ検索します。

  3. どんなものにも対処できるようにリファクタリングすることもできます(非常に簡単に) TextReader-たとえば、` StreamReader`-を介したテキスト入力。これにより、特定のファイルの内容全体をメモリにロードすることなく、巨大なファイルでも動作します。

このシナリオを想像してください。小説のテキスト全体を含むテキストファイルからテキストの抜粋を見つけたいとします。 (これはあなたのシナリオではありません-私は単に仮想的に話しているだけです)。さて、この場合、「StreamReader」は、必要なテキストが見つかるまで読み取りを要求するだけで、その時点で抜粋が返されます。

繰り返しますが、これは必ずしもあなたのシナリオではないことを理解しています-このアプローチがその強みの1つとして*スケーラビリティ*を提供することを示唆しているだけです。

'' '' '

これは簡単な実装です。

// rearranged code to avoid horizontal scrolling
public static string FindSurroundingLines
(string haystack, string needle, int paddingLines) {

    if (string.IsNullOrEmpty(haystack))
        throw new ArgumentException("haystack");
    else if (string.IsNullOrEmpty(needle))
        throw new ArgumentException("needle");
    else if (paddingLines < 0)
        throw new ArgumentOutOfRangeException("paddingLines");

    // buffer needs to accomodate paddingLines on each side
    // plus line containing the needle itself, so:
    // (paddingLines * 2) + 1
    int bufferSize = (paddingLines * 2) + 1;

    var buffer = new Queue(/*capacity*/ bufferSize);

    using (var reader = new StringReader(haystack)) {
        bool needleFound = false;

        while (!needleFound && reader.Peek() != -1) {
            string line = reader.ReadLine();

            if (buffer.Count == bufferSize)
                buffer.Dequeue();

            buffer.Enqueue(line);

            needleFound = line.Contains(needle);
        }

        // at this point either the needle has been found,
        // or we've reached the end of the text (haystack);
        // all that's left to do is make sure the string returned
        // includes the specified number of padding lines
        // on either side
        int endingLinesRead = 0;
        while (
            (reader.Peek() != -1 && endingLinesRead++ < paddingLines) ||
            (buffer.Count < bufferSize)
        ) {
            if (buffer.Count == bufferSize)
                buffer.Dequeue();

            buffer.Enqueue(reader.ReadLine());
        }

        var resultBuilder = new StringBuilder();
        while (buffer.Count > 0)
            resultBuilder.AppendLine(buffer.Dequeue());

        return resultBuilder.ToString();
    }
}

入力/出力の例(入力例を含む「テキスト」を使用):

コード:

Console.WriteLine(FindSurroundingLines(text, "MOUSE", 1);

出力:

This is the 2nd line of BIRD text in the paragraph
This is the 3rd line of MOUSE text in the paragraph
This is the 4th line of DOG text in the paragraph

コード:

Console.WriteLine(FindSurroundingLines(text, "BIRD", 1);

出力:

This is the 1st line of CAT text in the paragraph
This is the 2nd line of BIRD text in the paragraph
This is the 3rd line of MOUSE text in the paragraph

コード:

Console.WriteLine(FindSurroundingLines(text, "DOG", 0);

出力:

This is the 4th line of DOG text in the paragraph

コード:

 Console.WriteLine(FindSurroundingLines(text, "This", 2);

出力:

This is the 1st line of CAT text in the paragraph
This is the 2nd line of BIRD text in the paragraph
This is the 3rd line of MOUSE text in the paragraph
This is the 4th line of DOG text in the paragraph
This is the 5th line of RABBIT text in the paragraph


2


LINQ拡張メソッドを使用して適切な文字列を取得します。

string[] lines = text.Split('\n');

// Find the right line to work with
int position = 0;
for (int i = 0; i < lines.Count(); i++)
  if (lines[i].Contains(args[0]))
    position = i - 1;

// Get in range if we had a match in the first line
if (position == -1)
  position = 0;

// Adjust the line index so we have 3 lines to work with
if (position > lines.Count() - 3)
  position = lines.Count() - 3;

string result = String.Join("\n", lines.Skip(position).Take(3).ToArray());

もちろん、インデックスが見つかったらすぐにforループを終了することで、これを少し最適化できます。 おそらくLINQifyでさえできるので、余分な配列を実際に保存する必要はありませんが、今のところそれを行う良い方法は考えられません。

位置のチェックの代替手段は、 `position = Math.Max(0、Math.Min(position、lines.Count()-3));`のようなものです。これは両方を一度に処理します。


1


これを処理する方法はいくつかあります。

最初の方法: http://msdn.microsoft.com/en-us/library/system.string.indexof(v = VS.71).aspx [String.IndexOf()]およびhttp:// msdnを使用します。 microsoft.com/en-us/library/system.string.lastindexof(VS.71).aspx [String.LastIndexOf()]。

現在選択されている単語の場所は、http://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.selectionstart(v = VS.71).aspx [TextBox.SelectionStart( )]。 次に、選択場所からLastIndexOfを探して「\ n」を探し、前の行を見つけます(選択から最初のlastindexofをつかまないでください…​見つけたら、その場所からもう一度やり直してくださいその行の始まり)。 次に、IndexOfのみを使用して選択ポイントから同じ操作を実行し、 '\ n’を見つけて行の終わりを取得します。 繰り返しますが、最初に見つかったものを使用せずに、最初に見つかった場所から繰り返して2行目の終わりを取得します。 次に、見つけた領域でテキストを部分文字列化します。

  • 2番目の方法:*「\ n」文字でhttp://msdn.microsoft.com/en-us/library/system.string.split(v = VS.71).aspx [String.Split()]を使用します(文字列の配列を作成します。各配列には、配列インデックスの順序でテキストとは異なる行が含まれます)。 テキストが含まれる行のインデックスを見つけて、前、前、後の行のString [index]から取得します。 うまくいけば、この2つの方法が、コーディングを理解するのに十分明確であることを願っています。 それでも行き詰まっている場合は、お知らせください。


0


大丈夫です。 Lemmeには亀裂があり、

私が最初にすることは、すべてを配列に分割することだと思います。 単純に、行を「カウント」する簡単な方法があるからです。

string[] lines = fullstring.Split('\n');

残念ながら、配列の各ポイントを通過するindexofを知りません。 おそらく1つありますが、インターネットを介してトロールしないで、私は単に行きます

int i = -1;
string animal = 'bird';

foreach(string line in lines)
{
i++;
if(line.indexof(animal) > -1) break;

}
// we will need a if(i == -1) then we didn't find the animal etc

わかりましたので、ラインができました。 必要なのは…​

if(i == 0)
{
writeln(lines[0);
writeln(lines[1]);
etc
}
else
if(i == lines.count - 1)
{
//this means last array index
}
else
{
//else we are in the middle. So just write out the i -1, i, i+1
}

私はそれが地獄のように厄介であることを知っています。 しかし、それは私が問題を解決する方法です。