获取字符串中两个字符串之间的字符串


103

我有一个像这样的字符串:

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

我只想保留介于"key : "和之间的字符串" - "。我怎样才能做到这一点?我必须使用正则表达式还是可以其他方式使用它?


2
使用substringindexof
2013年

获得字符串和之前的另一个特定字符串特定字符串,它也包含在字符串中后的字符串,其中前者的字符串是..
肯健

Answers:


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
这将在内存中创建多个不需要的字符串。如果您在乎内存,请不要使用它。
MikaelDúiBolinder

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来自from,B直到直到,所以我删除了+ fromLength。我还没有进行深入测试
Adrian Iftode

1
@AdrianIftode:好的电话。这绝对是一个错误。从startIndex开始搜索第二个锚点是有意义的,因为它已经超过了第一个锚点的末尾。我已经在这里修复了代码。
ChaseMedallion

InvariantCulture不适用于Windows Universal Apps。有什么办法可以在保持班级功能的情况下将其删除?@ChaseMedallion
Leon

@Leon:您应该能够删除所有与区域性相关的内容,.NET只会将当前区域性用于indexOf操作。不过,我对Windows Universal Apps并不熟悉,所以我不确定。
ChaseMedallion

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 '18

10

正则表达式在这里过大了。

可以使用string.Split与需要过载string[]的分隔符,但会矫枉过正。

查看SubstringIndexOf-前者获得给定字符串的一部分,索引和长度,而前者获得内部字符串/字符的索引。


2
这不是矫kill过正……实际上,我会说Substring和IndexOf是矫kill过正。我会说那个字符串。拆分大约是正确的。正则表达式过大。
不是。

2
过大或过少的问题是没有意义的,因为答案可以满足发布者的要求,而不是正则表达式。
Karl Anderson

2
@newStackExchangeInstance:如果在“ key:”之前有“-”,它也会失败。子串是现货。
jmoreno 2013年

@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的开头返回冒号。
tsell 2013年

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

或者,使用正则表达式。

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响应(未加载JSON解析器)中提取access_token。我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

我同意。正如我提到的,这远非高效。我不建议使用此算法。这只不过是“”弱智化下来”,所以他能理解在一个较低的水平字符串如果他只是想完成任务,他已经有了答案,将实现这一目标。
flyNflip

我明白。我只是指出了它的强项和周点。虽然,要回答原始问题,还需要更多一点,因为它需要匹配字符串边界,而不仅仅是字符边界。但是想法是一样的。
Paulo Morgado

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在后面遇到一个或多个PPs,FF则在后面的PPs是子字符串的一部分。
  • 如果在遇到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)regex引擎对此进行了测试,但是由于regex一点都不陌生,因此我确信它可以与.NET 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(或更普遍地,该字符是构成下一个字符串的字符串),这种技术被称为“ 脾气暴躁的令牌解决方案”

自然,如果我上面提出的假设发生变化,则必须修改正则表达式(如果可能的话)。

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

有关详细信息,请参见文档

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.