Dapatkan string di antara dua string dalam satu string


103

Saya memiliki string seperti:

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

Saya hanya ingin menyimpan string yang berada di antara "key : "dan " - ". Bagaimana saya bisa melakukan itu? Haruskah saya menggunakan Regex atau dapatkah saya melakukannya dengan cara lain?


2
gunakan substringdanindexof
Sayse

Dapatkan string setelah string tertentu dalam sebuah string dan sebelum string spesifik lain yang juga terdapat dalam string tempat string sebelumnya berada ..
Ken Kin

Jawaban:


161

Mungkin, cara yang baik adalah dengan memotong substring :

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;

atau hanya dengan operasi string

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

29

Anda dapat melakukannya tanpa regex

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

6
Ini akan membuat beberapa string yang tidak dibutuhkan dalam memori. Jangan gunakan ini jika Anda peduli dengan memori.
Mikael Dúi Bolinder

14

Bergantung pada seberapa kuat / fleksibel implementasi yang Anda inginkan, ini sebenarnya bisa sedikit rumit. Berikut implementasi yang saya gunakan:

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 "

Saya menggunakan kode Anda, tetapi saya menemukan bug kecil ketika di @ this.IndexOf (sampai, startIndex + fromLength, perbandingan) dari string seperti "AB" di mana A berasal dan B adalah sampai, jadi saya menghapus + fromLength. Saya belum mengujinya secara mendalam
Adrian Iftode

1
@AdrianIftode: panggilan yang bagus. Ini pasti bug. Masuk akal untuk memulai pencarian jangkar kedua di startIndex, karena itu sudah melewati akhir jangkar pertama. Saya telah memperbaiki kodenya di sini.
ChaseMedallion

InvariantCulturetidak bekerja dengan Aplikasi Universal Windows. Apakah ada cara untuk menghapusnya dengan tetap mempertahankan fungsionalitas kelas Anda? @Chaseedion
Leon

@Leon: Anda harus dapat merobek semua hal yang berhubungan dengan budaya dan .NET hanya akan menggunakan budaya saat ini untuk operasi indexOf. Saya tidak terbiasa dengan Windows Universal Apps, jadi saya tidak bisa memastikannya.
ChaseMedallion

13

Inilah cara bagaimana saya bisa melakukan itu

   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

Saya pikir ini berhasil:

   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);                      
    }

Solusi bagus. Terima kasih!
arcee123

10

Regex berlebihan di sini.

Anda dapat menggunakan string.Splitdengan kelebihan beban yang membutuhkan string[]pembatas tetapi itu juga akan berlebihan.

Lihat Substringdan IndexOf- yang pertama untuk mendapatkan bagian dari string yang diberikan dan indeks dan panjang dan yang kedua untuk menemukan string / karakter dalam yang diindeks.


2
Ini tidak berlebihan ... sebenarnya saya akan mengatakan Substring dan IndexOf kurang dari itu. Saya akan mengatakan string itu. Perpecahan itu benar. Regex berlebihan.
It'sNotALie.

2
Maksud dari overkill atau under-kill diperdebatkan, karena jawabannya memenuhi permintaan poster untuk melakukannya dengan cara lain selain Regex.
Karl Anderson

2
@newStackExchangeInstance: ini juga gagal jika ada "-" sebelum "kunci:". Substring tepat.
jmoreno

@newStackExchangeInstance - Saya yakin yang dia bicarakan string.Split.
Oded

7

Solusi LINQ yang berfungsi:

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

Apakah ini hanya berfungsi untuk placeholder karakter tunggal?
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
Kode Anda akan menghasilkan titik dua yang dikembalikan di awal newString.
tsells

5

Karena :dan -unik, Anda dapat menggunakan:

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];

Jawaban ini tidak menambahkan sesuatu yang berarti pada jawaban yang sudah ada dalam jumlah besar.
Mephy

4

atau, dengan regex.

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;

dengan contoh berjalan .

Anda dapat memutuskan apakah itu berlebihan.

atau

sebagai metode ekstensi yang divalidasi di bawah

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 :)(.+?)(?=-)");

Ini hanya mengembalikan nilai antara "key:" dan kemunculan "-" berikut ini


3

Anda dapat menggunakan metode ekstensi di bawah ini:

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;
    }

Penggunaannya adalah:

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

3

Saya menggunakan potongan kode dari Vijay Singh Rana yang pada dasarnya melakukan pekerjaan itu. Tapi itu menyebabkan masalah jika firstStringmemang sudah mengandung lastString. Yang saya inginkan adalah mengekstrak access_token dari JSON Response (tidak ada JSON Parser yang dimuat). Saya firstStringdulu \"access_token\": \"dan saya lastStringdulu \". Saya berakhir dengan sedikit modifikasi

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
Ada redundansi. pos1 ditambahkan ke pos2, dan kemudian dikurangi dari pos2.
Jfly

Terima kasih, Anda benar. Saya mengoreksi contoh di atas.
nvm-uli

2

Jika Anda mencari solusi 1 baris, ini dia:

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

Seluruh solusi 1 baris, dengan 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

Anda sudah memiliki beberapa jawaban yang bagus dan saya menyadari kode yang saya berikan jauh dari yang paling efisien dan bersih. Namun, saya pikir ini mungkin berguna untuk tujuan pendidikan. Kita dapat menggunakan kelas dan perpustakaan yang telah dibuat sebelumnya sepanjang hari. Tetapi tanpa memahami cara kerja batin, kita hanya meniru dan mengulangi dan tidak akan pernah belajar apa pun. Kode ini berfungsi dan lebih mendasar atau "perawan" daripada beberapa yang lain:

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;
}

Anda berakhir dengan string yang Anda inginkan yang ditetapkan ke variabel parsedString. Ingatlah bahwa itu juga akan menangkap ruang depan dan sebelumnya. Ingatlah bahwa string hanyalah sebuah array karakter yang dapat dimanipulasi seperti array lain dengan indeks, dll.

Hati hati.


Ini adalah algoritma terbaik meski terburuk dalam pembuatan string. Semua jawaban yang disediakan tidak hanya regex yang memicu pembuatan string, tetapi yang ini adalah yang terburuk dari semua dalam pengertian itu. Jika Anda baru saja menangkap awal akhir string untuk menangkap dan menggunakan '' string.Substring '' untuk mengekstraknya, itu akan sempurna.
Paulo Morgado

Saya setuju. Seperti yang saya sebutkan, ini jauh dari efisien. Saya tidak akan merekomendasikan menggunakan algoritma ini. Ini hanyalah "" membodohi "sehingga dia dapat memahami string pada tingkat yang lebih rendah. Jika dia hanya ingin menyelesaikan pekerjaan, dia sudah memiliki jawaban yang akan mencapainya.
flyNflip

Saya mengerti itu. Saya hanya menunjukkan poin kuat dan mingguannya. Meskipun demikian, untuk menjawab pertanyaan awal dibutuhkan sedikit lebih banyak karena harus mencocokkan batas string dan bukan hanya batas karakter. Tapi idenya sama.
Paulo Morgado

1

Jika Anda ingin menangani beberapa kemunculan pasangan substring, tidak akan mudah tanpa RegEx:

Regex.Matches(input ?? String.Empty, "(?=key : )(.*)(?<= - )", RegexOptions.Singleline);
  • input ?? String.Empty menghindari pengecualian argumen nol
  • ?=mempertahankan substring pertama dan ?<=mempertahankan substring kedua
  • RegexOptions.Singleline memungkinkan baris baru di antara pasangan substring

Jika urutan & jumlah kemunculan substring tidak penting, yang cepat & kotor ini dapat menjadi pilihan:

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

Setidaknya ia menghindari sebagian besar pengecualian, dengan mengembalikan string asli jika tidak ada / satu substring yang cocok.


0

Seperti yang selalu saya katakan tidak ada yang tidak mungkin:

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);
}

Ingat itu harus menambahkan referensi System.Text.RegularExpressions

Harapan Bahwa Saya Membantu.


0

Sesuatu seperti ini mungkin

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

0

Ketika pertanyaan dinyatakan dalam satu contoh, ambiguitas pasti ada. Pertanyaan ini tidak terkecuali.

Untuk contoh yang diberikan dalam pertanyaan, string yang diinginkan jelas:

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

Namun, string ini hanyalah contoh string dan string batas di mana substring tertentu akan diidentifikasi. Saya akan mempertimbangkan string umum dengan string batas umum, yang direpresentasikan sebagai berikut.

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

PPadalah string sebelumnya , FFadalah string berikutnya dan topi pesta menunjukkan substring mana yang akan dicocokkan. (Dalam contoh yang diberikan dalam pertanyaan key : adalah string sebelumnya dan string -berikut.) Saya berasumsi bahwa PPdan FFdidahului dan diikuti oleh batas kata (sehingga PPAdan FF8tidak cocok).

Asumsi saya, sebagaimana tercermin dari topi pesta, adalah sebagai berikut:

  • Substring pertama PPmungkin didahului oleh satu (atau lebih) FFsubstring, yang jika ada, akan diabaikan;
  • Jika PPdiikuti oleh satu atau lebih PPs sebelum FFditemukan, PPs berikut adalah bagian dari substring antara string sebelum dan sesudahnya;
  • Jika PPdiikuti oleh satu atau lebih FFs sebelum a PPadalah ditemukan, yang pertama FFberikut PPdianggap sebagai string berikut.

Perhatikan bahwa banyak jawaban di sini hanya berurusan dengan string dalam bentuk

abc PP def FF ghi
      ^^^^^

atau

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

Seseorang dapat menggunakan ekspresi reguler, konstruksi kode, atau kombinasi keduanya untuk mengidentifikasi substring yang diminati. Saya tidak menilai pendekatan mana yang terbaik. Saya hanya akan menyajikan ekspresi reguler berikut yang akan cocok dengan substring yang diminati.

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

Nyalakan mesin Anda! 1

Saya menguji ini dengan mesin regex PCRE (PHP), tetapi karena regex sama sekali tidak eksotis, saya yakin ini akan bekerja dengan mesin regex .NET (yang sangat kuat).

Mesin regex melakukan operasi berikut:

(?<=          : 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

Teknik ini, mencocokkan satu karakter pada satu waktu, mengikuti string sebelumnya, hingga karakter tersebut Fdan diikuti oleh F(atau lebih umum lagi, karakter menjadi string yang membentuk string berikut), disebut Solusi Token Keserakahan Tempered .

Secara alami, regex harus dimodifikasi (jika memungkinkan) jika asumsi yang saya tetapkan di atas diubah.

1. Gerakkan kursor di sekitar untuk penjelasan rinci.


0

Di C # 8.0 dan di atasnya, Anda dapat menggunakan operator jangkauan ..seperti pada

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

Lihat dokumentasi untuk detailnya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.