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

163

我有一个字符串,类似于:

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

我想要保留在"key : "" - "之间的字符串。我该如何做?必须使用正则表达式吗?还有其他方法吗?


2
使用 substringindexof - Sayse
1
在一个字符串中获取特定字符串后面和另一个特定字符串前面的字符串,而这两个特定字符串都包含在前者所在的字符串中。 - Ken Kin
你还在尝试决定选择哪个答案吗? - Cary Swoveland
27个回答

251

也许,一种好的方法就是剪切出一个子字符串

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

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

35

你可以不使用正则表达式来完成它

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

13
如果您关心内存,就不要使用这种方法,因为它会在内存中创建多个不必要的字符串。 - Mikael Dúi Bolinder

27

这是我可以做到的方式

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

这是我在修复了许多问题后最终使用的代码。Bug:Pos2 应该是 STR.IndexOf(LastString, Pos1),以便从 Pos1 开始搜索。还需要进一步检查 0 Pos 值。 - user173399

19

根据您想要实现的强大/灵活程度,这可能会有些棘手。这是我使用的实现:

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 "

我使用了你的代码,但是在处理像“AB”这样的字符串时(其中A是from,B是until),我发现一个小错误出现在@this.IndexOf(until, startIndex + fromLength, comparison)。因此,我删除了+ fromLength。不过,我还没有进行深入测试。 - Adrian Iftode
1
@AdrianIftode:好的呼叫。这绝对是一个漏洞。从startIndex开始搜索第二个锚点是有意义的,因为那已经超过了第一个锚点的末尾。我已经在这里修复了代码。 - ChaseMedallion
InvariantCulture在Windows通用应用程序中无法正常工作。有没有办法在保持类的功能的同时删除它?@ChaseMedallion - Milon Sarker
@Leon:你应该能够剥离所有与文化相关的内容,.NET 将只使用当前文化来执行 indexOf 操作。不过,我不熟悉 Windows Universal Apps,所以不能确定。 - ChaseMedallion

18

我认为这个有效:

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

12

一个可行的LINQ解决方案:

string str = "super example 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
3
仅适用于单个字符,不符合OP的要求,应该被点踩。 - Max Alexander Hanna

11

在这里使用正则表达式过于复杂。

你可以使用带有 string[] 参数的 string.Split 重载方法,但那也会过于复杂。

查看 SubstringIndexOf - 前者用于获取给定索引和长度的字符串部分,后者用于查找内部字符串/字符的索引。


2
这并不是过度设计...事实上,我会说Substring和IndexOf是低配的。我认为string.Split是恰到好处的。正则表达式则有些过度了。 - It'sNotALie.
2
过度或不足的问题已经无关紧要了,因为答案满足了发帖者用另一种方式完成任务的要求,而不是使用正则表达式。 - Karl Anderson
2
@newStackExchangeInstance:如果在“key:”之前有“-”,它也会失败。 Substring是正确的。 - jmoreno
@newStackExchangeInstance - 我相信他在谈论 string.Split - Oded

8
在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

请查看文档以获取详细信息。

1
我喜欢C# 8及以上版本中的简写方法! - Kwex

6

我使用了来自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中减去了pos1。 - Feng Jiang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接