Pegue a string após uma determinada string em uma string e antes de outra string específica que também está contida na string onde a string anterior está.
Ken Kin
Respostas:
161
Talvez, uma boa maneira seja apenas cortar uma substring :
StringSt="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);
Isso criaria várias strings desnecessárias na memória. Não use isso se você se preocupa com a memória.
Mikael Dúi Bolinder
14
Dependendo de quão robusta / flexível você deseja que sua implementação seja, isso pode ser um pouco complicado. Esta é a implementação que uso:
publicstaticclassStringExtensions{/// <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>publicstaticstringSubstring(thisstring@this,stringfrom=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){thrownewArgumentException("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){thrownewArgumentException("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 "
Usei seu código, mas encontrei um pequeno bug quando em @ this.IndexOf (until, startIndex + fromLength, comparação) de strings como „AB” onde A é de e B é até, então removi + deLength. Eu não testei profundamente
Adrian Iftode
1
@AdrianIftode: boa chamada. Este era definitivamente um bug. Faz sentido iniciar a busca pela segunda âncora em startIndex, uma vez que já passou do final da primeira âncora. Corrigi o código aqui.
ChaseMedallion
InvariantCulturenão está funcionando com o Windows Universal Apps. Existe alguma maneira de removê-lo mantendo a funcionalidade de sua classe? @ChaseMedallion
Leon,
@Leon: você deve ser capaz de remover todas as coisas relacionadas à cultura e o .NET apenas usará a cultura atual para a operação indexOf. Não estou familiarizado com o Windows Universal Apps, portanto, não posso dizer com certeza.
Você poderia usar string.Splitcom a sobrecarga que exige um string[]para os delimitadores, mas isso também seria um exagero.
Olhe para Substringe IndexOf- o primeiro para obter partes de uma string fornecida e indexe um comprimento e o segundo para localizar strings / caracteres internos indexados.
Não é exagero ... na verdade, eu diria que Substring e IndexOf são underkill. Eu diria que string.Split está quase certo. Regex é um exagero.
It'sNotALie.
2
O ponto de ser um exagero ou subestimação é discutível, porque a resposta atende ao pedido do autor de fazer isso de uma maneira diferente do Regex.
Karl Anderson
2
@newStackExchangeInstance: também falha se houver um "-" antes da "chave:". A substring está correta.
jmoreno
@newStackExchangeInstance - Acho que ele está falando string.Split.
Oded de
7
Uma solução LINQ funcional:
string str ="super exemple of string key : text I want to keep - end of my string";string res =newstring(str.SkipWhile(c => c !=':').Skip(1).TakeWhile(c => c !='-').ToArray()).Trim();Console.WriteLine(res);// text I want to keep
Isso funciona apenas para marcadores de posição de um caractere?
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);
Seu código resultaria no retorno de dois pontos no início de newString.
tsells
5
Como o :e o -são exclusivos, você pode usar:
string input;string output;
input ="super example of string key : text I want to keep - end of my string";
output = input.Split(newchar[]{':','-'})[1];
Essa resposta não adiciona nada significativo à já grande quantidade de respostas existentes.
Mephy,
4
ou, com um regex.
using System.Text.RegularExpressions;...varvalue=Regex.Match("super exemple of string key : text I want to keep - end of my string","key : (.*) - ").Groups[1].Value;
using System.Text.RegularExpressions;publicclassTest{publicstaticvoidMain(){varvalue="super exemple of string key : text I want to keep - end of my string".Between("key : "," - ");Console.WriteLine(value);}}publicstaticclassExt{staticstringBetween(thisstring source,string left,string right){returnRegex.Match(
source,string.Format("{0}(.*){1}", left, right)).Groups[1].Value;}}
publicstaticstringGetStringBetween(thisstring 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;}
O uso é:
var token ="super exemple of string key : text I want to keep - end of my string";var keyValue = token.GetStringBetween("key : "," - ");
Usei o trecho de código de Vijay Singh Rana que basicamente faz o trabalho. Mas causará problemas se o firstStringjá contiver o lastString. O que eu queria era extrair um access_token de uma resposta JSON (sem JSON Parser carregado). Meu firstStringera \"access_token\": \"e meu lastStringera \". Acabei com uma pequena modificação
using System;
using System.Linq;classOneLiner{staticvoidMain(){string s ="TextHereTisImortant973End";//Between "eT" and "97"Console.WriteLine(s.Substring(s.IndexOf("eT")+"eT".Length).Split("97".ToCharArray()).First());}}
Você já tem algumas respostas boas e percebo que o código que estou fornecendo está longe de ser o mais eficiente e limpo. No entanto, pensei que poderia ser útil para fins educacionais. Podemos usar classes e bibliotecas pré-construídas o dia todo. Mas, sem entender o funcionamento interno, estamos simplesmente imitando e repetindo e nunca aprenderemos nada. Este código funciona e é mais básico ou "virgem" do que alguns dos outros:
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;}
Você acaba com a string desejada atribuída à variável parsedString. Lembre-se de que ele também capturará espaços anteriores e anteriores. Lembre-se de que uma string é simplesmente uma matriz de caracteres que pode ser manipulada como outras matrizes com índices etc.
Este é o melhor algoritmo, embora seja o pior na criação de strings. Todas as respostas fornecidas que não são apenas regex são acionadas pelo gatilho na criação de strings, mas esta é a pior de todas nesse sentido. Se você tivesse apenas capturado o início e o final da string para capturar e usado '' string.Substring '' para extraí-la, seria perfeito.
Paulo Morgado
Concordo. Como mencionei, está longe de ser eficiente. Eu não recomendaria usar este algoritmo. É simplesmente "emburrecer" para que ele possa entender strings em um nível inferior. Se ele simplesmente quiser fazer o trabalho, ele já tinha respostas que o alcançariam.
flyNflip
Eu entendi isso. Eu estava apenas apontando seus pontos fortes e fracos. Embora, para responder à pergunta original, seja necessário um pouco mais, pois precisa corresponder aos limites de uma string e não apenas aos limites dos caracteres. Mas a ideia é a mesma.
Paulo Morgado
1
Se você deseja lidar com várias ocorrências de pares de substring, não será fácil sem RegEx:
stringvalue="super exemple of string key : text I want to keep - end of my string";Regex regex =newRegex(@"(key \: (.*?) _ )");Match match = regex.Match(value);if(match.Success){Messagebox.Show(match.Value);}
Lembre-se de que deve adicionar referência de System.Text.RegularExpressions
Quando as perguntas são formuladas em termos de um único exemplo, as ambigüidades estão inevitavelmente presentes. Esta questão não é exceção.
Para o exemplo dado na pergunta, a string desejada é clara:
super example of string key : text I want to keep - end of my string^^^^^^^^^^^^^^^^^^^
No entanto, essa string é apenas um exemplo de strings e strings de limite para as quais certas substrings devem ser identificadas. Vou considerar uma string genérica com strings de fronteira genéricas, representadas da seguinte maneira.
PPé a string anterior , FFé a seguinte e os chapéus de festa indicam quais substrings devem ser combinadas. (No exemplo dado na pergunta key : é a string anterior e -é a seguinte.) Presumi que PPe FFsão precedidos e seguidos por limites de palavras (de modo que PPAe FF8não são correspondidos).
Minhas suposições, conforme refletidas pelos chapéus de festa, são as seguintes:
A primeira substring PPpode ser precedida por uma (ou mais) FFsubstrings, que, se presentes, são desconsideradas;
Se PPfor seguido por um ou mais PPs antes de FFser encontrado, os seguintes PPs são parte da substring entre as strings anteriores e seguintes;
Se PPfor seguido por um ou mais FFs antes de um PPencontro, o primeiro FFseguinte PPé considerado a seguinte string.
Observe que muitas das respostas aqui tratam apenas de strings da forma
abc PP def FF ghi
^^^^^
ou
abc PP def FF ghi PP jkl FF mno
^^^^^^^^^^
Pode-se usar uma expressão regular, construções de código ou uma combinação dos dois para identificar as substrings de interesse. Não faço nenhum julgamento sobre qual abordagem é a melhor. Apresentarei apenas a seguinte expressão regular que corresponderá às substrings de interesse.
Eu testei isso com o mecanismo regex PCRE (PHP), mas como o regex não é exótico, tenho certeza de que funcionará com o mecanismo regex .NET (que é muito robusto).
O mecanismo regex executa as seguintes operações:
(?<=: 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 group0+ times
(?=: begin positive lookahead
\bFF\b : match 'FF'): end positive lookahead
Esta técnica, de casar um caractere por vez, seguindo a string precedente, até que o caractere seja Fe seja seguido por F(ou mais geralmente, o caractere crie a string que constitui a string seguinte), é chamada de Solução de Token Guloso Temperado .
Naturalmente, a regex teria que ser modificada (se possível) se as suposições que estabeleci acima forem alteradas.
1. Mova o cursor para obter explicações detalhadas.
substring
eindexof
Respostas:
Talvez, uma boa maneira seja apenas cortar uma substring :
fonte
ou apenas com operações de string
fonte
Você pode fazer isso sem regex
fonte
Dependendo de quão robusta / flexível você deseja que sua implementação seja, isso pode ser um pouco complicado. Esta é a implementação que uso:
fonte
InvariantCulture
não está funcionando com o Windows Universal Apps. Existe alguma maneira de removê-lo mantendo a funcionalidade de sua classe? @ChaseMedallionAqui está a maneira como eu posso fazer isso
fonte
Eu acho que isso funciona:
fonte
Regex é um exagero aqui.
Você poderia usar
string.Split
com a sobrecarga que exige umstring[]
para os delimitadores, mas isso também seria um exagero.Olhe para
Substring
eIndexOf
- o primeiro para obter partes de uma string fornecida e indexe um comprimento e o segundo para localizar strings / caracteres internos indexados.fonte
string.Split
.Uma solução LINQ funcional:
fonte
fonte
Como o
:
e o-
são exclusivos, você pode usar:fonte
ou, com um regex.
com um exemplo em execução .
Você pode decidir se é um exagero.
ou
como um método de extensão validado
fonte
Isso retorna apenas o (s) valor (es) entre "chave:" e a seguinte ocorrência de "-"
fonte
Você pode usar o método de extensão abaixo:
O uso é:
fonte
Usei o trecho de código de Vijay Singh Rana que basicamente faz o trabalho. Mas causará problemas se o
firstString
já contiver olastString
. O que eu queria era extrair um access_token de uma resposta JSON (sem JSON Parser carregado). MeufirstString
era\"access_token\": \"
e meulastString
era\"
. Acabei com uma pequena modificaçãofonte
Se você está procurando uma solução de 1 linha, é isso:
A solução completa de 1 linha, com
System.Linq
:fonte
Você já tem algumas respostas boas e percebo que o código que estou fornecendo está longe de ser o mais eficiente e limpo. No entanto, pensei que poderia ser útil para fins educacionais. Podemos usar classes e bibliotecas pré-construídas o dia todo. Mas, sem entender o funcionamento interno, estamos simplesmente imitando e repetindo e nunca aprenderemos nada. Este código funciona e é mais básico ou "virgem" do que alguns dos outros:
Você acaba com a string desejada atribuída à variável parsedString. Lembre-se de que ele também capturará espaços anteriores e anteriores. Lembre-se de que uma string é simplesmente uma matriz de caracteres que pode ser manipulada como outras matrizes com índices etc.
Cuidar.
fonte
Se você deseja lidar com várias ocorrências de pares de substring, não será fácil sem RegEx:
Se a ordem e a contagem de ocorrências de substrings não importam, esta rápida e suja pode ser uma opção:
Pelo menos evita a maioria das exceções, retornando a string original se nenhuma / única substring corresponder.
fonte
Como sempre digo, nada é impossível:
Espero ter ajudado.
fonte
Algo assim talvez
fonte
Quando as perguntas são formuladas em termos de um único exemplo, as ambigüidades estão inevitavelmente presentes. Esta questão não é exceção.
Para o exemplo dado na pergunta, a string desejada é clara:
No entanto, essa string é apenas um exemplo de strings e strings de limite para as quais certas substrings devem ser identificadas. Vou considerar uma string genérica com strings de fronteira genéricas, representadas da seguinte maneira.
PP
é a string anterior ,FF
é a seguinte e os chapéus de festa indicam quais substrings devem ser combinadas. (No exemplo dado na perguntakey :
é a string anterior e-
é a seguinte.) Presumi quePP
eFF
são precedidos e seguidos por limites de palavras (de modo quePPA
eFF8
não são correspondidos).Minhas suposições, conforme refletidas pelos chapéus de festa, são as seguintes:
PP
pode ser precedida por uma (ou mais)FF
substrings, que, se presentes, são desconsideradas;PP
for seguido por um ou maisPP
s antes deFF
ser encontrado, os seguintesPP
s são parte da substring entre as strings anteriores e seguintes;PP
for seguido por um ou maisFF
s antes de umPP
encontro, o primeiroFF
seguintePP
é considerado a seguinte string.Observe que muitas das respostas aqui tratam apenas de strings da forma
ou
Pode-se usar uma expressão regular, construções de código ou uma combinação dos dois para identificar as substrings de interesse. Não faço nenhum julgamento sobre qual abordagem é a melhor. Apresentarei apenas a seguinte expressão regular que corresponderá às substrings de interesse.
Ligue seu motor! 1
Eu testei isso com o mecanismo regex PCRE (PHP), mas como o regex não é exótico, tenho certeza de que funcionará com o mecanismo regex .NET (que é muito robusto).
O mecanismo regex executa as seguintes operações:
Esta técnica, de casar um caractere por vez, seguindo a string precedente, até que o caractere seja
F
e seja seguido porF
(ou mais geralmente, o caractere crie a string que constitui a string seguinte), é chamada de Solução de Token Guloso Temperado .Naturalmente, a regex teria que ser modificada (se possível) se as suposições que estabeleci acima forem alteradas.
1. Mova o cursor para obter explicações detalhadas.
fonte
Em C # 8.0 e acima, você pode usar o operador de intervalo
..
como emConsulte a documentação para obter detalhes.
fonte