Bir dizedeki iki dizge arasındaki dizeyi alın


104

Şöyle bir dizem var:

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

Sadece "key : "ve arasındaki dizeyi tutmak istiyorum " - ". Bunu nasıl yapabilirim? Bir Normal İfade kullanmalı mıyım yoksa başka bir şekilde yapabilir miyim?


2
kullan substringveindexof
Sayse

Bir dizedeki belirli bir dizeden sonra ve yine eski dizenin bulunduğu dizede bulunan başka bir belirli dizeden önce dizeyi alın.
Ken Kin

Yanıtlar:


165

Belki de iyi bir yol, bir alt dizeyi kesmektir :

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;

veya sadece dizgi işlemleriyle

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

29

Bunu regex olmadan yapabilirsiniz

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

6
Bu, bellekte birden fazla gereksiz dizge oluşturacaktır. Hafızayı önemsiyorsanız bunu kullanmayın.
Mikael Dúi Bolinder

14

Uygulamanızın ne kadar sağlam / esnek olmasını istediğinize bağlı olarak, bu aslında biraz zor olabilir. İşte kullandığım uygulama:

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 "

Kodunuzu kullandım, ancak @ this.IndexOf konumunda küçük bir hata buldum (until, startIndex + fromLength, karşılaştırma) "AB" gibi dizelerden A'nın nereden ve B'nin de olduğu, bu yüzden + fromLength öğesini kaldırdım. Yine de derinlemesine test
etmedim

1
@AdrianIftode: iyi çağrı. Bu kesinlikle bir hataydı. İlk çapanın sonunu zaten geçmiş olduğundan, ikinci çapayı startIndex'te başlatmak mantıklıdır. Kodu burada düzelttim.
ChaseMedallion

InvariantCultureWindows Universal Apps ile çalışmıyor. Sınıfınızın işlevselliğini koruyarak onu kaldırmanın bir yolu var mı? @ChaseMedallion
Leon

@Leon: Kültürle ilgili tüm şeyleri kopyalayabilmelisiniz ve .NET, indexOf işlemi için sadece mevcut kültürü kullanacaktır. Yine de Windows Universal Uygulamalarına aşina değilim, bu yüzden kesin olarak söyleyemem.
ChaseMedallion

13

İşte bunu nasıl yapabileceğim

   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

Bunun işe yaradığını düşünüyorum:

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

Harika çözüm. Teşekkürler!
arcee123

10

Regex burada aşırıdır.

Sen olabilir kullanmak string.Splitbir sürer aşırı string[]sınırlayıcı için ama bu olurdu da overkill.

Bak Substringve IndexOf- belirli bir dizeye ve indeksi ve uzunluğu ve iç dizeleri / karakterleri endeksli bulmak için saniyenin parçaları almak için eski.


2
Bu aşırı değil ... Aslında Substring ve IndexOf'un zayıf olduğunu söyleyebilirim. Bu string.Split'in doğru olduğunu söyleyebilirim. Regex aşırıdır.
NotALie.

2
Aşırı öldürme veya yetersiz öldürme olmasının amacı tartışmalı çünkü cevap, posterin bunu Regex'ten başka bir şekilde yapma isteğini yerine getiriyor.
Karl Anderson

2
@newStackExchangeInstance: "anahtardan:" önce bir "-" varsa da başarısız olur. Alt dize yerinde.
jmoreno

@newStackExchangeInstance - Onun hakkında konuştuğuna inanıyorum string.Split.
2013

7

Çalışan bir LINQ çözümü:

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

Bu yalnızca tek karakterli yer tutucular için mi çalışır?
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
Kodunuz, iki nokta üst üste dizgesinin newString'in başında döndürülmesine neden olur.
2013

5

Yana :ve -benzersiz şunu kullanabilirsiniz:

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

Bu cevap, zaten büyük miktardaki mevcut cevaplara anlamlı bir şey katmaz.
Mephy

4

veya bir normal ifadeyle.

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;

bir ile çalışan, örneğin .

Aşırı olup olmadığına siz karar verebilirsiniz.

veya

doğrulanmamış bir uzantı yöntemi olarak

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

Bu yalnızca "key:" ile aşağıdaki "-" oluşumu arasındaki değerleri döndürür


3

Aşağıdaki uzantı yöntemini kullanabilirsiniz:

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

Kullanım:

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

3

Temelde işi yapan Vijay Singh Rana'dan kod parçacığını kullandım. Ancak firstString, zaten lastString. İstediğim şey, bir JSON Yanıtından bir erişim belirtecini çıkarmaktı (JSON Ayrıştırıcısı yüklenmemişti). Benim firstStringoldu \"access_token\": \"ve benim lastStringoldu \". Küçük bir değişiklik yaptım

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
Fazlalık var. pos1, pos2'ye eklendi ve ardından pos2'den çıkarıldı.
Jfly

Teşekkürler haklısın Yukarıdaki örneği düzelttim.
nvm-uli

2

1 satırlık bir çözüm arıyorsanız, bu:

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

1 hat çözümünün tamamı 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

Zaten bazı iyi yanıtlarınız var ve sağladığım kodun en verimli ve temiz olmaktan uzak olduğunu anlıyorum. Ancak eğitim amaçlı yararlı olabileceğini düşündüm. Önceden oluşturulmuş sınıfları ve kitaplıkları gün boyu kullanabiliriz. Ama içsel çalışmaları anlamadan, sadece taklit ediyoruz ve tekrarlıyoruz ve asla hiçbir şey öğrenmeyeceğiz. Bu kod çalışır ve diğerlerinden bazılarına göre daha basit veya "bakir":

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

İstediğiniz dizenin parsedString değişkenine atanmasıyla sonuçlanırsınız. Ayrıca ilerleyen ve önceki alanları da yakalayacağını unutmayın. Bir dizenin, indisli diğer diziler gibi değiştirilebilen bir karakter dizisi olduğunu unutmayın.

Kendine iyi bak.


Bu, dizi oluşturmada en kötüsü olmasına rağmen en iyi algoritmadır. Yalnızca normal ifade olmayan tüm yanıtlar, dizeleri oluşturmada tetikleyicidir, ancak bu, bu anlamda en kötüsüdür. Yakalamak için dizenin başlangıcını ve sonunu yakalamış olsaydınız ve onu çıkarmak için "string.Substring" i kullandıysanız, mükemmel olurdu.
Paulo Morgado

Katılıyorum. Bahsettiğim gibi, verimli olmaktan uzak. Bu algoritmayı kullanmanızı tavsiye etmem. Bu basitçe "" basitleştiriyor ", böylece dizeleri daha düşük bir seviyedeki anlayabilir. Sadece işi
bitirmek

Ben anladım. Ben sadece güçlü ve haftalık noktalarına işaret ediyordum. Bununla birlikte, orijinal soruyu cevaplamak için biraz daha fazlasını gerektirir, çünkü sadece karakter sınırlarını değil, bir dize sınırlarını da eşleştirmesi gerekir. Ama fikir aynı.
Paulo Morgado

1

Birden fazla alt dize çiftini işlemek istiyorsanız , RegEx olmadan kolay olmayacaktır:

Regex.Matches(input ?? String.Empty, "(?=key : )(.*)(?<= - )", RegexOptions.Singleline);
  • input ?? String.Empty argümanın boş istisnasını önler
  • ?=1. alt dizeyi ve ?<=2. alt dizeyi korur
  • RegexOptions.Singleline alt dize çifti arasında yeni satıra izin verir

Alt dizelerin sırası ve oluşum sayısı önemli değilse, bu hızlı ve kirli olan bir seçenek olabilir:

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

En azından, hiçbiri / tek alt dize eşleşirse orijinal dizeyi döndürerek çoğu istisnayı önler.


0

Her zaman söylediğim gibi hiçbir şeyin imkansız olmadığını:

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 başvurusunu eklemesi gerektiğini unutmayın

Umarım yardımcı oldum.


0

Belki bunun gibi bir şey

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

0

Sorular tek bir örnek üzerinden ifade edildiğinde kaçınılmaz olarak belirsizlikler vardır. Bu soru bir istisna değildir.

Soruda verilen örnek için istenen dizi açıktır:

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

Bununla birlikte, bu dize, belirli alt dizelerin tanımlanacağı dizelerin ve sınır dizelerinin bir örneğidir. Aşağıda gösterildiği gibi, genel sınır dizeleri olan genel bir dizeyi ele alacağım.

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

PPolduğu önceki dize , FFaşağıdaki dize ve parti şapkaları altdizgelerin eşleştirilecek olan göstermektedir. (Söz konusu Verilen örnekte key : önceki dizedir ve -aşağıdaki dizedir.) Bunu varsaydım PPve FFöncesinde ve (böylece sözcük sınırları tarafından takip edilmektedir PPAve FF8denk gelmiyor).

Parti şapkalarının yansıttığı şekliyle varsayımlarım şu şekildedir:

  • Birinci alt dizeden PPönce FF, varsa, dikkate alınmayan bir (veya daha fazla) alt dizi gelebilir ;
  • Eğer PPbir kişi tarafından takip ya da daha fazla olan PPdaha önce s FFkarşılaşıldığında, aşağıdaki PPs, ön ve son dizileri arasındaki substring bir parçasıdır;
  • Bir karşılaşmadan önce bir PPveya daha fazla FFs PPizliyorsa, ilk FFtakip PPeden aşağıdaki dize olarak kabul edilir.

Buradaki yanıtların çoğunun yalnızca formun dizeleriyle ilgili olduğuna dikkat edin

abc PP def FF ghi
      ^^^^^

veya

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

İlgili alt dizeleri tanımlamak için bir normal ifade, kod yapıları veya ikisinin bir kombinasyonu kullanılabilir. Hangi yaklaşımın en iyi olduğu konusunda hiçbir yargıya varmıyorum. Sadece ilgilenilen alt dizelerle eşleşen aşağıdaki normal ifadeyi sunacağım.

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

Motorunuzu çalıştırın! 1

Bunu PCRE (PHP) regex motoruyla test ettim, ancak regex hiç de egzotik olmadığından, .NET regex motoruyla (ki bu çok sağlam) çalışacağından eminim.

Normal ifade motoru aşağıdaki işlemleri gerçekleştirir:

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

Karakter gelene Fve onu takip edene kadar F(veya daha genel olarak karakter, aşağıdaki dizeyi oluşturan dizeyi oluşturur), her seferinde bir karakteri eşleştirme tekniğine Tempered Greedy Token Solution denir .

Doğal olarak, yukarıda belirttiğim varsayımlar değiştirilirse normal ifadenin (mümkünse) değiştirilmesi gerekir.

1. Ayrıntılı açıklamalar için imleci hareket ettirin.


0

C # 8.0 ve üzeri sürümlerde, aralık operatörünü aşağıdaki ..gibi kullanabilirsiniz

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

Ayrıntılar için belgelere bakın.


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

@KiranAmadipudi. StackOverflow'a hoş geldiniz. Lütfen önerdiğiniz çözümün OP'ye neden yardımcı olabileceğini düşündüğünüzü açıklayın.
Peter Csala
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.