文字列内の2つの文字列の間の文字列を取得する


102

私は次のような文字列を持っています:

"super exemple of string key : text I want to keep - end of my string"

私はちょうど間にある文字列を保持したい"key : "とし" - "。どうやってやるの?正規表現を使用する必要がありますか、それとも別の方法で実行できますか?


2
使用substringおよびindexof
Sayse

元の文字列が...である場合も、文字列に含まれる文字列で、別の特定の文字列の前に特定の文字列の後の文字列を取得します
ケンキン

回答:


160

おそらく、良い方法は、部分文字列を切り取ることです:

String St = "super exemple of string key : text I want to keep - end of my string";

int pFrom = St.IndexOf("key : ") + "key : ".Length;
int pTo = St.LastIndexOf(" - ");

String result = St.Substring(pFrom, pTo - pFrom);

37
string input = "super exemple of string key : text I want to keep - end of my string";
var match = Regex.Match(input, @"key : (.+?)-").Groups[1].Value;

または文字列操作のみ

var start = input.IndexOf("key : ") + 6;
var match2 = input.Substring(start, input.IndexOf("-") - start);

29

あなたは正規表現なしでそれを行うことができます

 input.Split(new string[] {"key :"},StringSplitOptions.None)[1]
      .Split('-')[0]
      .Trim();

5
これにより、メモリ内に複数の不要な文字列が作成されます。メモリが気になる場合は使用しないでください。
ミカエルドゥイブリンダー

14

実装の堅牢性/柔軟性に応じて、これは実際には少し難しい場合があります。これが私が使用する実装です:

public static class StringExtensions {
    /// <summary>
    /// takes a substring between two anchor strings (or the end of the string if that anchor is null)
    /// </summary>
    /// <param name="this">a string</param>
    /// <param name="from">an optional string to search after</param>
    /// <param name="until">an optional string to search before</param>
    /// <param name="comparison">an optional comparison for the search</param>
    /// <returns>a substring based on the search</returns>
    public static string Substring(this string @this, string from = null, string until = null, StringComparison comparison = StringComparison.InvariantCulture)
    {
        var fromLength = (from ?? string.Empty).Length;
        var startIndex = !string.IsNullOrEmpty(from) 
            ? @this.IndexOf(from, comparison) + fromLength
            : 0;

        if (startIndex < fromLength) { throw new ArgumentException("from: Failed to find an instance of the first anchor"); }

            var endIndex = !string.IsNullOrEmpty(until) 
            ? @this.IndexOf(until, startIndex, comparison) 
            : @this.Length;

        if (endIndex < 0) { throw new ArgumentException("until: Failed to find an instance of the last anchor"); }

        var subString = @this.Substring(startIndex, endIndex - startIndex);
        return subString;
    }
}

// usage:
var between = "a - to keep x more stuff".Substring(from: "-", until: "x");
// returns " to keep "

私はあなたのコードを使用しましたが、@ this.IndexOf(until、startIndex + fromLength、Comparison)at likeAB”のような文字列から小さなバグを見つけました。私はそれを深くテストしていません
エイドリアン・イフトエー2013年

1
@AdrianIftode:良い電話。これは間違いなくバグでした。startIndexで2番目のアンカーの検索を開始することは理にかなっています。これは、最初のアンカーの終わりをすでに過ぎているためです。ここでコードを修正しました。
ChaseMedallion 2013年

InvariantCultureはWindows Universal Appsと連携していません。クラスの機能を維持したままそれを削除する方法はありますか?@ChaseMedallion
Leon

@Leon:カルチャに関連するすべてのものを取り除くことができ、.NETはindexOf操作に現在のカルチャを使用するだけです。私はWindows Universal Appsに慣れていないので、はっきりとは言えません。
ChaseMedallion 2015

13

これが私がそれを行う方法です

   public string Between(string STR , string FirstString, string LastString)
    {       
        string FinalString;     
        int Pos1 = STR.IndexOf(FirstString) + FirstString.Length;
        int Pos2 = STR.IndexOf(LastString);
        FinalString = STR.Substring(Pos1, Pos2 - Pos1);
        return FinalString;
    }

13

私はこれがうまくいくと思います:

   static void Main(string[] args)
    {
        String text = "One=1,Two=2,ThreeFour=34";

        Console.WriteLine(betweenStrings(text, "One=", ",")); // 1
        Console.WriteLine(betweenStrings(text, "Two=", ",")); // 2
        Console.WriteLine(betweenStrings(text, "ThreeFour=", "")); // 34

        Console.ReadKey();

    }

    public static String betweenStrings(String text, String start, String end)
    {
        int p1 = text.IndexOf(start) + start.Length;
        int p2 = text.IndexOf(end, p1);

        if (end == "") return (text.Substring(p1));
        else return text.Substring(p1, p2 - p1);                      
    }

素晴らしいソリューション。ありがとう!
arcee123 2018

10

ここで正規表現はやりすぎです。

あなたは可能性が使用string.Split受け取るオーバーロードでstring[]区切り文字のためにそれは考えやり過ぎ。

Substringandを見てくださいIndexOf-前者は与えられた文字列の一部とインデックスと長さを取得するためのもので、2番目は内部の文字列/文字のインデックスを見つけるためのものです。


2
それはやり過ぎではありません...実際、SubstringとIndexOfはやりすぎです。そのstring.Splitはほぼ正しいと思います。正規表現はやりすぎです。
それはNotALieです。

2
答えが正規表現以外の方法でそれを行うというポスターの要求を満たしているので、それが過剰または不足であるという意味は意味がない。
カールアンダーソン

2
@newStackExchangeInstance:「-」が「キー:」の前にある場合も失敗します。サブストリングはスポットです。
jmoreno 2013年

@newStackExchangeInstance-彼が話していると思いますstring.Split
13:18に

7

機能するLINQソリューション:

string str = "super exemple of string key : text I want to keep - end of my string";
string res = new string(str.SkipWhile(c => c != ':')
                           .Skip(1)
                           .TakeWhile(c => c != '-')
                           .ToArray()).Trim();
Console.WriteLine(res); // text I want to keep

これは1文字のプレースホルダーでのみ機能しますか?
beppe9000

5
 string str="super exemple of string key : text I want to keep - end of my string";
        int startIndex = str.IndexOf("key") + "key".Length;
        int endIndex = str.IndexOf("-");
        string newString = str.Substring(startIndex, endIndex - startIndex);

1
コードの結果、コロンがnewStringの先頭に返されます。
tsells 2013年

5

:-は一意であるため、使用できます。

string input;
string output;
input = "super example of string key : text I want to keep - end of my string";
output = input.Split(new char[] { ':', '-' })[1];

この回答は、すでに大量の既存の回答に意味のあるものを追加するものではありません。
Mephy、2015

4

または、正規表現を使用します。

using System.Text.RegularExpressions;

...

var value =
    Regex.Match(
        "super exemple of string key : text I want to keep - end of my string",
        "key : (.*) - ")
    .Groups[1].Value;

実行している例

あなたはそのやり過ぎかどうかを決めることができます。

または

検証不足の拡張メソッドとして

using System.Text.RegularExpressions;

public class Test
{
    public static void Main()
    {
        var value =
                "super exemple of string key : text I want to keep - end of my string"
                    .Between(
                        "key : ",
                        " - ");

        Console.WriteLine(value);
    }
}

public static class Ext
{
    static string Between(this string source, string left, string right)
    {
        return Regex.Match(
                source,
                string.Format("{0}(.*){1}", left, right))
            .Groups[1].Value;
    }
}

4
var matches = Regex.Matches(input, @"(?<=key :)(.+?)(?=-)");

これは、「key:」と次の「-」の出現の間の値のみを返します


3

以下の拡張メソッドを使用できます。

public static string GetStringBetween(this string token, string first, string second)
    {            
        if (!token.Contains(first)) return "";

        var afterFirst = token.Split(new[] { first }, StringSplitOptions.None)[1];

        if (!afterFirst.Contains(second)) return "";

        var result = afterFirst.Split(new[] { second }, StringSplitOptions.None)[0];

        return result;
    }

使い方は:

var token = "super exemple of string key : text I want to keep - end of my string";
var keyValue = token.GetStringBetween("key : ", " - ");

3

私は基本的に仕事をするVijay Singh Ranaからのコードスニペットを使用しました。ただし、にfirstString既にが含まれている場合、問題が発生しますlastString。私が欲しかったのは、JSONレスポンスからaccess_tokenを抽出することでした(JSONパーサーが読み込まれていません)。私はfirstStringだった\"access_token\": \"と私lastStringでした\"。少し修正してしまいました

string Between(string str, string firstString, string lastString)
{    
    int pos1 = str.IndexOf(firstString) + firstString.Length;
    int pos2 = str.Substring(pos1).IndexOf(lastString);
    return str.Substring(pos1, pos2);
}

1
冗長性があります。pos1がpos2に追加され、pos2から差し引かれました。
Jfly

ありがとう、あなたは正しい。上記の例を修正しました。
nvm-uli

2

あなたが1行の解決策を探しているなら、これはそれです:

s.Substring(s.IndexOf("eT") + "eT".Length).Split("97".ToCharArray()).First()

全体の1行のソリューションSystem.Linq

using System;
using System.Linq;

class OneLiner
{
    static void Main()
    {
        string s = "TextHereTisImortant973End"; //Between "eT" and "97"
        Console.WriteLine(s.Substring(s.IndexOf("eT") + "eT".Length)
                           .Split("97".ToCharArray()).First());
    }
}

1

あなたはすでにいくつかの良い答えを持っています、そして私が提供しているコードは最も効率的でクリーンなものからはほど遠いことに気づきました。しかし、それは教育目的に役立つかもしれないと思いました。ビルド済みのクラスとライブラリを1日中使用できます。しかし、内部の仕組みを理解しないと、私たちは単に模倣して繰り返し、何も学ぶことはありません。このコードは機能し、他のいくつかのコードよりも基本的または「未使用」です。

char startDelimiter = ':';
char endDelimiter = '-';

Boolean collect = false;

string parsedString = "";

foreach (char c in originalString)
{
    if (c == startDelimiter)
         collect = true;

    if (c == endDelimiter)
         collect = false;

    if (collect == true && c != startDelimiter)
         parsedString += c;
}

parsedString変数に割り当てられた目的の文字列で終了します。前後のスペースもキャプチャされることに注意してください。文字列は、インデックスなどを持つ他の配列と同様に操作できる単なる文字の配列であることを忘れないでください。

気を付けて。


文字列の作成は最悪ですが、これは最良のアルゴリズムです。正規表現のみではないすべての回答は、文字列を作成するのにトリガーハッピーですが、これはその意味ですべての最悪です。キャプチャする文字列の最初と最後をキャプチャし、 '' string.Substring ''を使用して抽出した場合、それは完璧です。
Paulo Morgado 2013年

同意する。私が述べたように、それは効率的ではありません。このアルゴリズムの使用はお勧めしません。。彼は低いレベルでの文字列を理解できるように、彼は単に彼はすでにそれを達成するであろう答えを持っていた、仕事を得るしたい場合には、「それをdumbing」」単純である。
flyNflip

私は理解した。私はその強力なポイントと週のポイントを指摘していました。ただし、元の質問に答えるには、文字の境界だけでなく文字列の境界と一致する必要があるため、もう少し必要です。しかし、考え方はまったく同じです。
Paulo Morgado 2013年

1

サブストリングペアの複数のオカレンスを処理する場合、RegExなしでは簡単ではありません。

Regex.Matches(input ?? String.Empty, "(?=key : )(.*)(?<= - )", RegexOptions.Singleline);
  • input ?? String.Empty 引数のnull例外を回避
  • ?=最初のサブストリングを?<=保持し、2番目のサブストリングを保持
  • RegexOptions.Singleline 部分文字列ペア間の改行を許可します

部分文字列の順序と出現回数が重要でない場合は、この迅速でダーティなものをオプションにすることができます。

var parts = input?.Split(new string[] { "key : ", " - " }, StringSplitOptions.None);
string result = parts?.Length >= 3 ? result[1] : input;

少なくとも、一致する部分文字列が1つもない場合に元の文字列を返すことで、ほとんどの例外を回避します。


0

いつも言っているように、不可能はありません。

string value =  "super exemple of string key : text I want to keep - end of my string";
Regex regex = new Regex(@"(key \: (.*?) _ )");
Match match = regex.Match(value);
if (match.Success)
{
    Messagebox.Show(match.Value);
}

System.Text.RegularExpressionsの参照を追加する必要があるRemeber

私が助けてくれたことを願っています。


0

おそらくこのようなもの

private static string Between(string text, string from, string to)
{
    return text[(text.IndexOf(from)+from.Length)..text.IndexOf(to, text.IndexOf(from))];
}

0

質問が単一の例に関して述べられるとき、あいまいさが必ず存在します。この質問も例外ではありません。

質問の例では、目的の文字列は明確です。

super example of string key : text I want to keep - end of my string
                              ^^^^^^^^^^^^^^^^^^^

ただし、この文字列は、特定の部分文字列が識別される文字列と境界文字列の例にすぎません。次のように表される、一般的な境界文字列を持つ一般的な文字列を検討します。

abc FF def PP ghi,PP jkl,FF mno PP pqr FF,stu FF vwx,PP yza
             ^^^^^^^^^^^^         ^^^^^  

PP前の文字列FFは次の文字列であり、パーティーハットは照合するサブ文字列を示します。(質問の例でkey : は、前の文字列と-次の文字列です。)私はとの前後に単語の境界が続くPPと想定していFFます(そのため、PPAFF8は一致しません)。

党の帽子に反映されている私の仮定は次のとおりです。

  • 最初の部分文字列のPP前に1つ(または複数)のFF部分文字列を付けることができますが、存在しても無視されます。
  • の前にPP1つ以上PPのs が続く場合FF、次PPのは、先行する文字列と後続の文字列の間の部分文字列の一部です。
  • の前にPP1つ以上FFのが続く場合PP、最初のFF後続PPは次の文字列と見なされます。

ここでの回答の多くは次の形式の文字列のみを扱うことに注意してください

abc PP def FF ghi
      ^^^^^

または

abc PP def FF ghi PP jkl FF mno
      ^^^^^         ^^^^^

正規表現、コード構成、またはこの2つの組み合わせを使用して、対象のサブストリングを識別できます。私はどちらのアプローチが最善であるかについては判断しません。対象の部分文字列に一致する次の正規表現のみを提示します。

(?<=\bPP\b)(?:(?!\bFF\b).)*(?=\bFF\b)

エンジンをかけよう!1

私はPCRE(PHP)正規表現エンジンでこれをテストしましたが、正規表現はまったくエキゾチックではないので、.NET正規表現エンジン(非常に堅牢)で動作するはずです。

正規表現エンジンは次の操作を実行します。

(?<=          : begin a positive lookbehind
  \bPP\b      : match 'PP'
)             : end positive lookbehind
(?:           : begin a non-capture group
  (?!         : begin a negative lookahead
    \bFF\b    : match 'FF'
  )           : end negative lookahead
  .           : match any character
)             : end non-capture group
*             : execute non-capture group 0+ times
(?=           : begin positive lookahead
   \bFF\b     : match 'FF'
)             : end positive lookahead

前の文字列に続いて、その文字Fが続くまでF(または、より一般的には、文字が次の文字列を構成する文字列である)、一度に1文字ずつ照合するこの手法は、Tempered Greedy Token Solutionと呼ばれます。

当然のことながら、上で述べた仮定が変更された場合、(可能であれば)正規表現を変更する必要があります。

1.詳細な説明については、カーソルを動かしてください。


0

C#8.0以降では、次のように範囲演算子..を使用できます

var s = "header-THE_TARGET_STRING.7z";
var from = s.IndexOf("-") + "-".Length;
var to = s.IndexOf(".7z");
var versionString = s[from..to];  // THE_TARGET_STRING

詳細については、ドキュメントを参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.