Mam taki ciąg:
"super exemple of string key : text I want to keep - end of my string"
Chcę po prostu zachować ciąg znajdujący się między "key : "a " - ". Jak mogę to zrobić? Czy muszę używać Regex, czy mogę to zrobić w inny sposób?
Mam taki ciąg:
"super exemple of string key : text I want to keep - end of my string"
Chcę po prostu zachować ciąg znajdujący się między "key : "a " - ". Jak mogę to zrobić? Czy muszę używać Regex, czy mogę to zrobić w inny sposób?
Odpowiedzi:
Być może dobrym sposobem jest po prostu wycięcie podciągu :
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);
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;
lub tylko z operacjami na łańcuchach
var start = input.IndexOf("key : ") + 6;
var match2 = input.Substring(start, input.IndexOf("-") - start);
Możesz to zrobić bez wyrażenia regularnego
input.Split(new string[] {"key :"},StringSplitOptions.None)[1]
.Split('-')[0]
.Trim();
W zależności od tego, jak solidna / elastyczna ma być Twoja implementacja, może to być trochę trudne. Oto implementacja, której używam:
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 "
InvariantCulturenie działa z aplikacjami uniwersalnymi systemu Windows. Czy jest jakiś sposób, aby go usunąć, zachowując funkcjonalność swojej klasy? @ChaseMedallion
Oto sposób, w jaki mogę to zrobić
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;
}
Myślę, że to działa:
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);
}
Regex to przesada.
Państwo mogli korzystać string.Splitz przeciążeniem, które odbywają się string[]na ograniczniki ale to też być przesadą.
Spójrz na Substringi IndexOf- pierwsze, aby uzyskać części podanego ciągu i indeksu oraz długość, a drugie, aby znaleźć indeksowane wewnętrzne ciągi / znaki.
string.Split.
Działające rozwiązanie 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
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);
Ponieważ :i -są unikalne, możesz użyć:
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];
lub z wyrażeniem regularnym.
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;
Możesz zdecydować, czy to przesada.
jako niedostatecznie zwalidowana metoda rozszerzenia
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;
}
}
Możesz skorzystać z poniższej metody rozszerzenia:
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;
}
Wykorzystanie to:
var token = "super exemple of string key : text I want to keep - end of my string";
var keyValue = token.GetStringBetween("key : ", " - ");
Użyłem fragmentu kodu z Vijay Singh Rana, który w zasadzie spełnia swoje zadanie. Ale powoduje problemy, jeśli firstStringplik zawiera już rozszerzenie lastString. Chciałem wyodrębnić access_token z odpowiedzi JSON (nie załadowano parsera JSON). Moje firstStringbyło \"access_token\": \"i moje lastStringbyło \". Skończyło się na niewielkiej modyfikacji
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);
}
Jeśli szukasz rozwiązania 1-liniowego, oto jest:
s.Substring(s.IndexOf("eT") + "eT".Length).Split("97".ToCharArray()).First()
Całe rozwiązanie 1-liniowe z 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());
}
}
Masz już kilka dobrych odpowiedzi i zdaję sobie sprawę, że kod, który dostarczam, jest daleki od najbardziej wydajnego i czystego. Pomyślałem jednak, że może to być przydatne do celów edukacyjnych. Możemy używać gotowych klas i bibliotek przez cały dzień. Ale bez zrozumienia wewnętrznego działania po prostu naśladujemy i powtarzamy i nigdy się niczego nie nauczymy. Ten kod działa i jest bardziej podstawowy lub „dziewiczy” niż niektóre inne:
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;
}
Kończysz z żądanym ciągiem przypisanym do zmiennej parsedString. Należy pamiętać, że przechwytuje również pola poprzedzające i poprzedzające. Pamiętaj, że ciąg to po prostu tablica znaków, którymi można manipulować jak innymi tablicami z indeksami itp.
Dbać.
Jeśli chcesz obsłużyć wiele wystąpień par podciągów, nie będzie to łatwe bez wyrażenia regularnego:
Regex.Matches(input ?? String.Empty, "(?=key : )(.*)(?<= - )", RegexOptions.Singleline);
input ?? String.Emptyunika wyjątku zerowego argumentu?=zachowuje pierwszy podciąg i?<=zachowuje drugi podciągRegexOptions.Singlelinedopuszcza znak nowej linii między parą podciągów
Jeśli kolejność i liczba wystąpień podciągów nie ma znaczenia, ten szybki i brudny może być opcją:
var parts = input?.Split(new string[] { "key : ", " - " }, StringSplitOptions.None);
string result = parts?.Length >= 3 ? result[1] : input;
Przynajmniej unika większości wyjątków, zwracając oryginalny ciąg, jeśli żaden / pojedynczy podciąg nie pasuje.
Jak zawsze powtarzam, nie ma rzeczy niemożliwych:
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);
}
Pamiętaj, że powinno dodać odwołanie do System.Text.RegularExpressions
Mam nadzieję, że pomogłem.
Może coś takiego
private static string Between(string text, string from, string to)
{
return text[(text.IndexOf(from)+from.Length)..text.IndexOf(to, text.IndexOf(from))];
}
Gdy pytania są zadawane w kategoriach pojedynczego przykładu, nieuchronnie pojawiają się niejasności. To pytanie nie jest wyjątkiem.
Dla przykładu podanego w pytaniu pożądany ciąg jest jasny:
super example of string key : text I want to keep - end of my string
^^^^^^^^^^^^^^^^^^^
Jednak ten ciąg jest tylko przykładem łańcuchów i ciągów granicznych, dla których mają zostać zidentyfikowane określone podciągi. Rozważę ogólny ciąg z ogólnymi łańcuchami granicznymi, przedstawionymi w następujący sposób.
abc FF def PP ghi,PP jkl,FF mno PP pqr FF,stu FF vwx,PP yza
^^^^^^^^^^^^ ^^^^^
PPjest poprzedzającym ciągiem , FFjest następującym ciągiem, a kapelusze imprezowe wskazują, które podciągi mają zostać dopasowane. (W przykładzie podanym w pytaniu key : jest poprzedzający ciąg i -jest to następujący ciąg.) Założyłem to PPi FFsą poprzedzone i zakończone granicami słów (tak, że PPAi FF8nie są dopasowane).
Moje założenia, które odzwierciedlają czapki imprezowe, są następujące:
PPmoże być poprzedzony jednym (lub więcej) FFpodciągami, które, jeśli są obecne, są pomijane;PPnastępuje jedno lub więcej PPs przed FFnapotkaniem, następujące PPs są częścią podłańcucha między poprzedzającym a następnym ciągiem;PPnastępuje jedno lub więcej FFs przed PPspotkaniem, pierwszy FFnastępujący po nim PPjest uważany za następujący ciąg.Zwróć uwagę, że wiele odpowiedzi tutaj dotyczy tylko ciągów znaków formularza
abc PP def FF ghi
^^^^^
lub
abc PP def FF ghi PP jkl FF mno
^^^^^ ^^^^^
Można użyć wyrażenia regularnego, konstrukcji kodu lub kombinacji tych dwóch w celu zidentyfikowania interesujących nas podciągów. Nie oceniam, które podejście jest najlepsze. Przedstawię tylko następujące wyrażenie regularne, które będzie pasowało do interesujących nas podciągów.
(?<=\bPP\b)(?:(?!\bFF\b).)*(?=\bFF\b)
Przetestowałem to z silnikiem regex PCRE (PHP), ale ponieważ wyrażenie regularne wcale nie jest egzotyczne, jestem pewien, że będzie działać z silnikiem regex .NET (który jest bardzo solidny).
Silnik wyrażeń regularnych wykonuje następujące operacje:
(?<= : 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
Ta technika polega na dopasowywaniu jednego znaku na raz, po poprzedzającym ciągu, aż do znaku Fi następuje po nimF (lub bardziej ogólnie, znak jest łańcuchem, który tworzy następujący ciąg), nazywa się Tempered Greedy Token Solution .
Oczywiście regex musiałby zostać zmodyfikowany (jeśli to możliwe), gdyby zmienione zostały założenia, które przedstawiłem powyżej.
1. Poruszaj kursorem, aby uzyskać szczegółowe wyjaśnienia.
W C # 8,0 i nowszych można użyć operatora zakresu, ..tak jak w
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
Szczegółowe informacje można znaleźć w dokumentacji .
substringiindexof