รับสตริงระหว่างสองสตริงในสตริง


107

ฉันมีสตริงเช่น:

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

ฉันต้องการเพียงแค่ให้สตริงซึ่งอยู่ระหว่างและ"key : " " - "ฉันจะทำเช่นนั้นได้อย่างไร? ฉันต้องใช้ Regex หรือฉันสามารถทำได้ด้วยวิธีอื่น?


2
การใช้งานsubstringและindexof
Sayse

รับสตริงหลังสตริงเฉพาะในสตริงและก่อนสตริงเฉพาะอื่นซึ่งมีอยู่ในสตริงที่สตริงเดิมอยู่ใน ..
Ken Kin

คำตอบ:


171

บางทีวิธีที่ดีก็แค่ตัดสตริงย่อยออก:

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

38
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

คุณสามารถทำได้โดยไม่ต้อง regex

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

6
สิ่งนี้จะสร้างสตริงที่ไม่จำเป็นหลายรายการในหน่วยความจำ อย่าใช้สิ่งนี้หากคุณสนใจเรื่องความจำ
Mikael Dúi Bolinder

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, การเปรียบเทียบ) จากสตริงเช่น "AB" โดยที่ A มาจากและ B คือจนถึงดังนั้นฉันจึงลบ + จากLength ฉันยังไม่ได้ทดสอบมันอย่างลึกซึ้ง
Adrian Iftode

1
@AdrianIftode: โทรดี นี่เป็นข้อบกพร่องอย่างแน่นอน ควรเริ่มการค้นหาจุดยึดที่สองที่ startIndex เนื่องจากผ่านจุดสิ้นสุดของจุดยึดแรกไปแล้ว ฉันแก้ไขรหัสที่นี่แล้ว
ChaseMedallion

InvariantCultureไม่ทำงานกับ Windows Universal Apps มีวิธีใดบ้างที่จะลบออกโดยรักษาฟังก์ชันการทำงานของชั้นเรียนไว้ @ChaseMedallion
Leon

@ Leon: คุณควรจะสามารถคัดลอกสิ่งที่เกี่ยวข้องกับวัฒนธรรมทั้งหมดออกมาได้และ. NET จะใช้วัฒนธรรมปัจจุบันสำหรับการดำเนินการ indexOf ฉันไม่คุ้นเคยกับ Windows Universal Apps ดังนั้นฉันจึงไม่สามารถพูดได้อย่างแน่นอน
ChaseMedallion

14

ฉันคิดว่ามันได้ผล:

   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

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

10

Regex อยู่ที่นี่มากเกินไป

คุณสามารถใช้string.Splitกับโอเวอร์โหลดที่ใช้string[]สำหรับตัวคั่น แต่ก็จะมากเกินไปเช่นกัน

ดูSubstringและIndexOf- ก่อนหน้านี้เพื่อรับส่วนของสตริงที่กำหนดและดัชนีและความยาวและส่วนที่สองสำหรับการค้นหาสตริง / อักขระภายใน


2
มันไม่ได้มากเกินไป ... อันที่จริงฉันจะบอกว่า Substring และ IndexOf อยู่ในระดับต่ำ ฉันจะบอกว่า string.Split ถูกต้อง Regex มีการใช้งานมากเกินไป
It'sNotALie

2
ประเด็นของการ overkill หรือ under-kill คือการสงสัยเพราะคำตอบตอบสนองคำขอของผู้โพสต์ในการทำวิธีอื่นที่ไม่ใช่ Regex
Karl Anderson

2
@newStackExchangeInstance: มันจะล้มเหลวหากมี "-" อยู่ข้างหน้า "คีย์:" สตริงย่อยเป็นจุด
jmoreno

@newStackExchangeInstance - string.Splitผมเชื่อว่าเขาจะพูดคุยเกี่ยวกับ
Oded

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

สิ่งนี้ใช้ได้กับตัวยึดตำแหน่งอักขระเดี่ยวเท่านั้นหรือไม่
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

5

หรือด้วยนิพจน์ทั่วไป

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

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

4

คุณสามารถใช้วิธีการขยายด้านล่าง:

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 : ", " - ");

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

สิ่งนี้จะส่งกลับเฉพาะค่าระหว่าง "คีย์:" และการเกิดขึ้นต่อไปนี้ของ "-"


4

ฉันใช้ข้อมูลโค้ดจาก Vijay Singh Rana ซึ่งโดยทั่วไปแล้วจะได้ผล แต่จะทำให้เกิดปัญหาหากมีfirstStringอยู่แล้วlastString. สิ่งที่ฉันต้องการคือการแยก access_token จากการตอบกลับ JSON (ไม่มีการโหลดตัวแยกวิเคราะห์ 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

3

หากคุณกำลังมองหาโซลูชัน 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());
    }
}

2

ใน 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

ดูเอกสารสำหรับรายละเอียด


ฉันชอบวิธีมือสั้นใน C # 8 ขึ้นไป!
Kwex

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

ฉันเห็นด้วย. ดังที่ได้กล่าวไปแล้วมันยังห่างไกลจากประสิทธิภาพ ฉันไม่แนะนำให้ใช้อัลกอริทึมนี้ มันเป็นเพียงแค่ "" โง่ลง "เพื่อให้เขาเข้าใจสตริงในระดับที่ต่ำกว่าหากเขาต้องการทำงานให้ลุล่วงเขาก็มีคำตอบที่จะบรรลุเป้าหมายนั้นแล้ว
flyNflip

ฉันเข้าใจแล้ว ฉันแค่ชี้ให้เห็นจุดแข็งและสัปดาห์ แม้ว่าในการตอบคำถามเดิมจะต้องใช้เวลาอีกเล็กน้อยเนื่องจากต้องตรงกับขอบเขตสตริงไม่ใช่แค่ขอบเขตอักขระ แต่ความคิดก็เหมือนกัน
Paulo Morgado

1

หากคุณต้องการจัดการคู่สตริงย่อยที่เกิดขึ้นหลายคู่มันจะไม่ง่ายเลยหากไม่มี RegEx:

Regex.Matches(input ?? String.Empty, "(?=key : )(.*)(?<= - )", RegexOptions.Singleline);
  • input ?? String.Empty หลีกเลี่ยงข้อยกเว้นที่เป็นโมฆะของอาร์กิวเมนต์
  • ?=เก็บสตริงย่อยที่ 1 และ?<=คงสตริงย่อยที่ 2
  • RegexOptions.Singleline อนุญาตให้ขึ้นบรรทัดใหม่ระหว่างคู่สตริงย่อย

หากลำดับและจำนวนการเกิดสตริงย่อยไม่สำคัญตัวเลือกที่รวดเร็วและสกปรกนี้อาจเป็นตัวเลือก:

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

อย่างน้อยที่สุดก็จะหลีกเลี่ยงข้อยกเว้นโดยส่งคืนสตริงเดิมหากไม่มี / สตริงย่อยที่ตรงกัน


1
  private string gettxtbettwen(string txt, string first, string last)
    {

        StringBuilder sb = new StringBuilder(txt);
        int pos1 = txt.IndexOf(first)  + first.Length;
        int len = (txt.Length ) - pos1;

        string reminder = txt.Substring(pos1, len);


        int pos2 = reminder.IndexOf(last) - last.Length +1;


       



        return reminder.Substring(0, pos2); 



    }

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

หวังว่าฉันจะช่วย


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จะนำหน้าและตามด้วยขอบเขตของคำ (เพื่อให้PPAและFF8ไม่ตรง)

สมมติฐานของฉันซึ่งสะท้อนให้เห็นโดยหมวกปาร์ตี้มีดังนี้:

  • สตริงย่อยแรกPPอาจนำหน้าด้วยสตริงย่อยหนึ่งตัว (หรือมากกว่า) FFซึ่งถ้ามีอยู่จะถูกละเว้น
  • ถ้าPPตามด้วยหนึ่งหรือมากกว่าPPก่อนFFจะพบPPs ต่อไปนี้เป็นส่วนหนึ่งของสตริงย่อยระหว่างสตริงก่อนหน้าและสตริงต่อไปนี้
  • หากPPตามด้วยหนึ่งหรือมากกว่านั้นFFก่อนที่PPจะพบรายการFFต่อไปนี้PPจะถือเป็นสตริงต่อไปนี้

โปรดทราบว่าคำตอบจำนวนมากที่นี่จัดการกับสตริงของฟอร์มเท่านั้น

abc PP def FF ghi
      ^^^^^

หรือ

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

หนึ่งอาจใช้นิพจน์ทั่วไปโครงสร้างโค้ดหรือการรวมกันของทั้งสองเพื่อระบุสตริงย่อยที่สนใจ ฉันไม่ตัดสินว่าแนวทางใดดีที่สุด ฉันจะนำเสนอเฉพาะนิพจน์ทั่วไปต่อไปนี้ที่ตรงกับสตริงย่อยที่สนใจ

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

สตาร์ทเครื่องยนต์ของคุณ! 1

ฉันทดสอบสิ่งนี้ด้วยเอนจิ้น regex PCRE (PHP) แต่เนื่องจาก regex ไม่ได้แปลกใหม่เลยฉันมั่นใจว่ามันจะทำงานร่วมกับเอนจิ้น. NET regex (ซึ่งแข็งแกร่งมาก)

เอนจิน regex ดำเนินการดังต่อไปนี้:

(?<=          : 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(หรือมากกว่าโดยทั่วไปสิ่งมีชีวิตตัวละครสตริงที่ถือว่าเป็นสตริงต่อไปนี้) จะเรียกว่านิรภัยโซลูชั่น Token โลภ

ตามปกติแล้ว regex จะต้องได้รับการแก้ไข (ถ้าเป็นไปได้) หากสมมติฐานที่ฉันตั้งไว้ข้างต้นมีการเปลี่ยนแปลง

1. เลื่อนเคอร์เซอร์ไปรอบ ๆ เพื่อดูคำอธิบายโดยละเอียด


-1
getStringBetween(startStr, endStr, fullStr) {
    string startIndex = fullStr.indexOf(startStr);
    string endIndex= fullStr.indexOf(endStr);
    return fullStr.substring(startIndex + startStr.length, endIndex);
}

@KiranAmadipudi. ยินดีต้อนรับสู่ StackOverflow โปรดให้คำอธิบายว่าเหตุใดคุณจึงคิดว่าโซลูชันที่คุณเสนออาจช่วย OP ได้
Peter Csala
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.