如何提取括号(圆括号)之间的文本?

Posted

技术标签:

【中文标题】如何提取括号(圆括号)之间的文本?【英文标题】:How do I extract text that lies between parentheses (round brackets)? 【发布时间】:2010-09-27 13:32:04 【问题描述】:

我有一个字符串User name (sales),我想提取括号之间的文本,我该怎么做?

我怀疑子字符串,但直到右括号我才知道如何阅读,文本的长度会有所不同。

【问题讨论】:

向我们展示您的尝试。你看过使用正则表达式吗? 【参考方案1】:

如果你想远离正则表达式,我能想到的最简单的方法是:

string input = "User name (sales)";
string output = input.Split('(', ')')[1];

【讨论】:

老实说,这应该被选为答案。 不是进一步收缩成input.Split("()".ToCharArray())[1] 如果你想使用相同的逻辑来选择多个:var input = "(fdw) User name (sales) safdsdf (again?)"; var output = input.Split('(', ')').Where((item, index) => index % 2 != 0).ToList(); 请注意,此解决方案还会从包含 )sales((sales( 等的输入字符串中提取 sales 简单答案,最佳答案+1【参考方案2】:

一个非常简单的方法是使用正则表达式:

Regex.Match("User name (sales)", @"\(([^)]*)\)").Groups[1].Value

作为对(非常有趣的)评论的回应,这里是相同的正则表达式和一些解释:

\(             # Escaped parenthesis, means "starts with a '(' character"
    (          # Parentheses in a regex mean "put (capture) the stuff 
               #     in between into the Groups array" 
       [^)]    # Any character that is not a ')' character
       *       # Zero or more occurrences of the aforementioned "non ')' char"
    )          # Close the capturing group
\)             # "Ends with a ')' character"

【讨论】:

我喜欢人们说“一种简单的方法是使用正则表达式”,然后提供相当于一串难以理解的象形文字(当不同的人建议使用正则表达式并且每个人都想出一个同一问题的不同象形文字集)。 :) 堆栈上几乎没有足够的答案来真正解释发生了什么。 感谢您的精彩解释。 如果您在开头使用'@',我认为您不需要转义括号? @rank1 你必须转义括号。 @ 在这里提供的是您不需要转义反斜杠。所以如果没有@,它就像“\\(([^)]*)\\)”。 这并不能很好地处理嵌套组。改为var filterRegex = new Regex(Regex.Escape("(") + "([^()]*)" + Regex.Escape(")")); 【参考方案3】:

假设你只有一对括号。

string s = "User name (sales)";
int start = s.IndexOf("(") + 1;
int end = s.IndexOf(")", start);
string result = s.Substring(start, end - start);

【讨论】:

如果您想要“sales”而不是(sales),则子字符串中的 start+1 更正确 会发生什么 s= "User ) name (Sales)"? @dotnetstep 你是对的应该是int end = s.IndexOf(")", start);。我已将编辑排队... "(".Length; 比 +1 好。发送了一个编辑。还添加了一个功能。【参考方案4】:

使用此功能:

public string GetSubstringByString(string a, string b, string c)
    
        return c.Substring((c.IndexOf(a) + a.Length), (c.IndexOf(b) - c.IndexOf(a) - a.Length));
    

这是用法:

GetSubstringByString("(", ")", "User name (sales)")

输出将是:

sales

【讨论】:

【参考方案5】:

正则表达式可能是这里最好的工具。如果您不熟悉它们,我建议您安装 Expresso - 一个很棒的小正则表达式工具。

类似:

Regex regex = new Regex("\\((?<TextInsideBrackets>\\w+)\\)");
string incomingValue = "Username (sales)";
string insideBrackets = null;
Match match = regex.Match(incomingValue);
if(match.Success)

    insideBrackets = match.Groups["TextInsideBrackets"].Value;

【讨论】:

正则表达式不支持嵌套【参考方案6】:

也许是一个正则表达式?我认为这会起作用...

\(([a-z]+?)\)

【讨论】:

【参考方案7】:
string input = "User name (sales)";

string output = input.Substring(input.IndexOf('(') + 1, input.IndexOf(')') - input.IndexOf('(') - 1);

【讨论】:

你当然应该只计算第一个括号的位置一次。 如果你有内括号,例如input = "User name (sales(1)) 您可能想使用input.LastIndexOf(')'),无论是否有内括号都可以使用。【参考方案8】:
using System;
using System.Text.RegularExpressions;

private IEnumerable<string> GetSubStrings(string input, string start, string end)

    Regex r = new Regex(Regex.Escape(start) +`"(.*?)"`  + Regex.Escape(end));
    MatchCollection matches = r.Matches(input);
    foreach (Match match in matches)
    yield return match.Groups[1].Value;

【讨论】:

【参考方案9】:
int start = input.IndexOf("(") + 1;
int length = input.IndexOf(")") - start;
output = input.Substring(start, length);

【讨论】:

【参考方案10】:

使用正则表达式:

string test = "(test)"; 
string word = Regex.Match(test, @"\((\w+)\)").Groups[1].Value;
Console.WriteLine(word);

【讨论】:

【参考方案11】:
input.Remove(input.IndexOf(')')).Substring(input.IndexOf('(') + 1);

【讨论】:

【参考方案12】:

我认为regex 方法更好,但如果你想使用不起眼的substring

string input= "my name is (Jayne C)";
int start = input.IndexOf("(");
int stop = input.IndexOf(")");
string output = input.Substring(start+1, stop - start - 1);

string input = "my name is (Jayne C)";
string output  = input.Substring(input.IndexOf("(") +1, input.IndexOf(")")- input.IndexOf("(")- 1);

【讨论】:

【参考方案13】:

这是一个避免使用正则表达式的通用可读函数:

// Returns the text between 'start' and 'end'.
string ExtractBetween(string text, string start, string end)

  int iStart = text.IndexOf(start);
  iStart = (iStart == -1) ? 0 : iStart + start.Length;
  int iEnd = text.LastIndexOf(end);
  if(iEnd == -1)
  
    iEnd = text.Length;
  
  int len = iEnd - iStart;

  return text.Substring(iStart, len);

要在您的特定示例中调用它,您可以这样做:

string result = ExtractBetween("User name (sales)", "(", ")");

【讨论】:

【参考方案14】:

我发现正则表达式非常有用,但很难编写。所以,我做了一些研究,发现tool 让编写它们变得如此简单。

不要回避它们,因为语法很难理解。它们可以如此强大。

【讨论】:

欢迎来到 SO!这是一个很好的建议,但它不应该作为答案发布。像这样的一般建议应该作为 cmets 发布,如果有的话。答案必须解决提问者的具体问题。我知道您还没有足够的声望点来发布 cmets,但这正是存在代表阈值的原因。当您使用一段时间后,您会发现人们总是推荐像 Rubular 这样的工具(当然是在 cmets 中)。换句话说,这个建议可能有用,但并不紧急。【参考方案15】:

我最近一直在使用和滥用 C#9,即使在有问题的情况下,我也情不自禁地投入 Spans... 只是为了好玩,以下是上述答案的变体:

    var input = "User name (sales)";
    var txtSpan = input.AsSpan();
    var startPoint = txtSpan.IndexOf('(') + 1;
    var length = txtSpan.LastIndexOf(')') - startPoint;
    var output = txtSpan.Slice(startPoint, length);

对于 OP 的特定场景,它会产生正确的输出。 (就我个人而言,我会使用其他人发布的 RegEx。更容易绕过上述解决方案崩溃的更棘手的场景。

我为自己的项目制作的更好的版本(作为扩展方法):

//Note: This only captures the first occurrence, but 
//can be easily modified to scan across the text (I'd prefer Slicing a Span)  
public static string ExtractFromBetweenChars(this string txt, char openChar, char closeChar)

    ReadOnlySpan<char> span = txt.AsSpan();
    int firstCharPos = span.IndexOf(openChar);
    int lastCharPos = -1;

    if (firstCharPos != -1) 
     
        for (int n = firstCharPos + 1; n < span.Length; n++)
        
            if (span[n] == openChar) firstCharPos = n; //This allows the opening char position to change
            if (span[n] == closeChar) lastCharPos = n;
            if (lastCharPos > firstCharPos) break;
            //This would correctly extract "sales" from this [contrived]
            //example: "just (a (name (sales) )))(test"
        
        return span.Slice(firstCharPos + 1, lastCharPos - firstCharPos - 1).ToString();
    
    return "";

【讨论】:

这是我的投票,看看使用 Span 如何在这种情况下获得最佳性能。【参考方案16】:

这段代码比这里的大多数解决方案更快(如果不是全部),打包为Stringextension method,它不支持递归嵌套:

public static string GetNestedString(this string str, char start, char end)

    int s = -1;
    int i = -1;
    while (++i < str.Length)
        if (str[i] == start)
        
            s = i;
            break;
        
    int e = -1;
    while(++i < str.Length)
        if (str[i] == end)
        
            e = i;
            break;
        
    if (e > s)
        return str.Substring(s + 1, e - s - 1);
    return null;

这个有点长和慢,但它更好地处理递归嵌套:

public static string GetNestedString(this string str, char start, char end)

    int s = -1;
    int i = -1;
    while (++i < str.Length)
        if (str[i] == start)
        
            s = i;
            break;
        
    int e = -1;
    int depth = 0;
    while (++i < str.Length)
        if (str[i] == end)
        
            e = i;
            if (depth == 0)
                break;
            else
                --depth;
        
        else if (str[i] == start)
            ++depth;
    if (e > s)
        return str.Substring(s + 1, e - s - 1);
    return null;

【讨论】:

【参考方案17】:

与@Gustavo Baiocchi Costa 非常相似,但偏移量是使用另一个中间值Substring 计算的。

int innerTextStart = input.IndexOf("(") + 1;
int innerTextLength = input.Substring(start).IndexOf(")");
string output = input.Substring(innerTextStart, innerTextLength);

【讨论】:

【参考方案18】:

我在寻找非常相似的实现的解决方案时遇到了这个问题。

这是我实际代码中的一个 sn-p。从第一个字符(索引 0)开始子字符串。

 string separator = "\n";     //line terminator

 string output;
 string input= "HowAreYou?\nLets go there!";

 output = input.Substring(0, input.IndexOf(separator)); 

【讨论】:

这没有回答 OP 的要求。

以上是关于如何提取括号(圆括号)之间的文本?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式提取方括号之间的文本[重复]

PHP中大括号之间的匹配文本

sql 在SQL SERVER中的括号之间提取文本

在R中,如何提取所有文本直到左括号?

用于在最后一个括号 () 之间获取文本的正则表达式

正则表达式提取大括号之间的数据并加载到 AMQ