문자열에서 두 문자열 사이의 문자열 가져 오기


103

다음과 같은 문자열이 있습니다.

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

"key : "와 사이에있는 문자열을 유지하고 싶습니다 " - ". 어떻게 할 수 있습니까? 정규식을 사용해야합니까 아니면 다른 방법으로 수행 할 수 있습니까?


2
사용 substring하고indexof
Sayse

문자열의 특정 문자열 뒤와 이전 문자열이있는 문자열에도 포함 된 다른 특정 문자열 앞의 문자열을 가져옵니다.
Ken Kin

답변:


161

아마도 좋은 방법은 하위 문자열 을 잘라내는 것입니다 .

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;

또는 문자열 연산만으로

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

29

정규식없이 할 수 있습니다.

 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, comparison)에서 A가 시작되고 B가까지 인 "AB"와 같은 문자열에서 작은 버그를 발견 했으므로 + fromLength를 제거했습니다. 나는 깊은 생각을 테스트하지 않았습니다
아드리안 Iftode에게

1
@AdrianIftode : 좋은 전화입니다. 이것은 확실히 버그였습니다. startIndex에서 두 번째 앵커에 대한 검색을 시작하는 것이 좋습니다. 이미 첫 번째 앵커의 끝을 지났기 때문입니다. 여기서 코드를 수정했습니다.
ChaseMedallion 2010 년

InvariantCultureWindows Universal Apps에서 작동하지 않습니다. 클래스의 기능을 유지하면서 제거 할 수있는 방법이 있습니까? @ChaseMedallion
레온

@Leon : 모든 문화 관련 항목을 제거 할 수 있어야하며 .NET은 indexOf 작업에 현재 문화권을 사용합니다. 하지만 Windows Universal Apps에 익숙하지 않기 때문에 확실히 말할 수는 없습니다.
ChaseMedallion 2015-09-17

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

13

나는 이것이 작동한다고 생각한다.

   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

10

여기서 정규식은 과잉입니다.

당신은 할 수 사용 string.Split걸리는 과부하 string[]구분 기호에 대한하지만 것 또한 과잉합니다.

SubstringIndexOf- 주어진 문자열과 인덱스와 길이 및 내부 문자열 / 문자의 색인을 찾기위한 두 번째의 일부를 얻을 전자를.


2
그것은 과잉이 아닙니다 ... 사실 Substring과 IndexOf가 과소 평가된다고 말할 것입니다. 나는 그 문자열이라고 말하고 싶습니다. 정규식은 과잉입니다.
NotALie입니다.

2
그 대답이 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 2017-10-06

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

이후 :와는 -고유 당신은 사용할 수 있습니다 :

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 2015-04-08

4

또는 정규식으로.

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

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

이것은 "key :"와 다음 "-"발생 사이의 값만 반환합니다.


3

아래 확장 방법을 사용할 수 있습니다.

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

3

기본적으로 작업을 수행하는 Vijay Singh Rana의 코드 스 니펫을 사용했습니다. 그러나에 firstString이미 lastString. 내가 원했던 것은 JSON 응답에서 access_token을 추출하는 것입니다 (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

2

단선 솔루션을 찾고 있다면 다음과 같습니다.

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

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 2013 년

나는 동의한다. 내가 언급했듯이 효율적이지 않습니다. 이 알고리즘을 사용하지 않는 것이 좋습니다. 그는 낮은 수준에서 문자열을 이해할 수 있도록 단순히 ""멍청이 "일뿐입니다. 그가 단순히 일을 끝내고 자한다면 그는 이미 그것을 달성 할 수있는 답을 가지고있었습니다.
flyNflip

나는 그것을 이해했다. 나는 단지 그것의 강점과 주 포인트를 지적하고 있었다. 원래 질문에 대답하려면 문자 경계뿐만 아니라 문자열 경계와 일치해야하므로 조금 더 필요합니다. 하지만 아이디어는 똑같습니다.
Paulo Morgado 2013 년

1

하위 문자열 쌍의 여러 항목 을 처리하려는 경우 RegEx 없이는 쉽지 않습니다.

Regex.Matches(input ?? String.Empty, "(?=key : )(.*)(?<= - )", RegexOptions.Singleline);
  • input ?? String.Empty 인수 null 예외 방지
  • ?=첫 번째 부분 문자열을 ?<=유지하고 두 번째 부분 문자열을 유지합니다.
  • RegexOptions.Singleline 하위 문자열 쌍 사이에 줄 바꿈 허용

하위 문자열의 순서 및 발생 횟수가 중요하지 않은 경우이 빠르고 더러운 것이 옵션 일 수 있습니다.

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

적어도 일치하는 부분 문자열이 하나도 없으면 원래 문자열을 반환하여 대부분의 예외를 피합니다.


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 : 앞의 문자열이고 -다음과 같은 문자열입니다.) 나는 가정 한 PPFF선행과 (그래서 단어 경계가옵니다 PPAFF8일치하지 않습니다).

파티 모자에 반영된 내 가정은 다음과 같습니다.

  • 첫 번째 부분 문자열 PP앞에는 하나 (또는 ​​그 이상의) FF부분 문자열이 올 수 있으며, 존재하는 경우 무시됩니다.
  • 경우 PP한 뒤에 이상 PP전에 s의 FF발생은 다음 PP들 이전 및 다음 문자열의 문자열의 일부이고;
  • a 가 만나기 전에 PP하나 이상의 FFs 가 뒤에 오는 경우 PP첫 번째 FF다음 PP은 다음 문자열로 간주됩니다.

여기에있는 많은 답변은 다음 형식의 문자열 만 다룹니다.

abc PP def FF ghi
      ^^^^^

또는

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

관심있는 부분 문자열을 식별하기 위해 정규식, 코드 구조 또는 두 가지 조합을 사용할 수 있습니다. 나는 어떤 접근법이 가장 좋은지 판단하지 않습니다. 관심있는 부분 문자열과 일치하는 다음 정규식 만 제시하겠습니다.

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

엔진 시동! 1

나는 이것을 PCRE (PHP) 정규식 엔진으로 테스트했지만 정규식이 전혀 이국적이지 않기 때문에 .NET 정규식 엔진 (매우 강력 함)에서 작동 할 것이라고 확신합니다.

정규식 엔진은 다음 작업을 수행합니다.

(?<=          : 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(또는보다 일반적으로 문자가 다음 문자열을 구성하는 문자열이 됨) Tempered Greedy Token Solution 이라고 합니다.

당연히 위에서 설명한 가정이 변경되면 정규식을 수정해야합니다 (가능한 경우).

1. 자세한 설명을 보려면 커서를 이동하십시오.


0

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

자세한 내용은 설명서 를 참조하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.