Как извлечь текст, заключенный в круглые скобки?


224

У меня есть строка, User name (sales)и я хочу извлечь текст в скобках, как мне это сделать?

Я подозреваю, что подстрока, но я не могу понять, как читать до закрывающей скобки, длина текста будет меняться.


2
Покажите нам, что вы пытались. Вы смотрели на использование регулярных выражений?
Джордж Стокер

Ответы:


445

Если вы хотите избежать регулярных выражений, самый простой способ, который я могу придумать:

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

91
Честно говоря, это должно было быть выбрано в качестве ответа.
Пэт Линдли

1
Разве это не будет дополнительно заключено в input.Split ("()". ToCharArray ()) [1]
prabhakaran

14
и в случае, если вы хотите использовать одну и ту же логику для выбора нескольких:var input = "(fdw) User name (sales) safdsdf (again?)"; var output = input.Split('(', ')').Where((item, index) => index % 2 != 0).ToList();
WtFudgE

1
имейте в виду, что это решение извлекает salesтакже из входных строк, содержащих )sales(, и (sales(т. д.
Стефано Спинуччи

435

Очень простой способ сделать это с помощью регулярных выражений:

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

В качестве ответа на (очень забавный) комментарий приведем того же Regex с некоторыми пояснениями:

\(             # 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"

504
Мне нравится, когда люди говорят, что «простой способ - использовать регулярные выражения», а затем предлагают то, что составляет цепочку неразборчивых иероглифов (особенно забавно, когда разные люди предлагают регулярное выражение, и каждый из них предлагает свой набор иероглифов для одной и той же проблемы. ). :)
Deltics

47
В стеке недостаточно ответов, которые на самом деле объясняют, что происходит. Спасибо за чудесное объяснение.
Сэнди Гиффорд

Если вы используете «@» в начале, я думаю, вам не нужно избегать скобок?
ранг 1

10
@ ранг1 ты должен избегать скобок. Здесь @ предлагает то, что вам не нужно избегать обратной косой черты. Так что без @ это было бы как "\\ (([^)] *) \\)".
Диадистис

Это не очень хорошо обрабатывает вложенные группы. Изменено наvar filterRegex = new Regex(Regex.Escape("(") + "([^()]*)" + Regex.Escape(")"));
Jan Van der Haegen

91

Предполагая, что у вас есть только одна пара скобок.

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

7
начало + 1 в подстроке правильнее, если вы хотите «продажи» вместо (продажи)
Joze

1
что произойдет с s = "User) name (Sales)"?
dotnetstep

@dotnetstep ты прав должен быть int end = s.IndexOf(")", start);. Я
поставил в

1
"(". Длина; лучше +1. Отправил правку. Также добавлена ​​функция.
Аве

24

Используйте эту функцию:

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

16

Регулярные выражения могут быть лучшим инструментом здесь. Если вы не знакомы с ними, я рекомендую вам установить 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;
}

14
string input = "User name (sales)";

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

1
Вы, конечно, должны только рассчитать местоположение первой скобки один раз.
Мартин Браун

В случае, когда у вас есть внутренние скобки, например, input = "User name (sales(1))вы можете использовать, input.LastIndexOf(')')который будет работать, если есть внутренние скобки или нет.
Бен

13

Может быть, регулярное выражение? Я думаю, что это будет работать ...

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

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

4

Используйте регулярное выражение:

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



2

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

1

Вот читаемая функция общего назначения, которая избегает использования регулярных выражений:

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

1

Я считаю, что регулярные выражения чрезвычайно полезны, но их очень сложно написать. Итак, я провел небольшое исследование и нашел этот инструмент, который делает их написание настолько простым.

Не уклоняйтесь от них, потому что синтаксис трудно понять. Они могут быть такими сильными.


2
Добро пожаловать на ТАК! Это хороший совет, но его не следовало публиковать в качестве ответа. Общие советы, подобные этому, следует публиковать в виде комментариев, если они вообще есть. Ответ должен адресовать конкретную проблему спрашивающего. Я знаю, что у вас недостаточно очков репутации, чтобы оставлять комментарии, но именно поэтому существует порог повторения. Пройдя немного дольше, вы увидите, что люди всегда рекомендуют такие инструменты, как Rubular (в комментариях, конечно). Другими словами, этот совет может быть полезен, но это не срочно.
Алан Мур

0

Я сталкивался с этим, когда искал решение для очень похожей реализации.

Вот фрагмент из моего фактического кода. Начинает подстроку с первого символа (индекс 0).

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

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

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

Это не отвечает на то, что спросил ОП.
кубик

0

Этот код быстрее, чем большинство решений здесь (если не все), упакован как метод расширения String , он не поддерживает рекурсивное вложение:

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;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.