Як витягти текст, що лежить між дужками (круглі дужки)?


224

У мене є рядок, User name (sales)і я хочу витягнути текст між дужками, як би це зробити?

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


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

Відповіді:


445

Якщо ви хочете триматися подалі від регулярних виразів, найпростіший спосіб, який я можу придумати, це:

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

91
Чесно кажучи, це було обрано як відповідь.
Пат Ліндлі

1
Хіба це не далі стягується в input.Split ( "()" ToCharArray ().) [1]
Прабхакаран

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(т.д.
Stefano Spinucci

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
Мені подобається, коли люди кажуть "простий спосіб - використовувати регулярні вирази", а потім пропонують те, що становить рядок нерозбірливих ієрогліфів (особливо цікаво, коли різні люди пропонують регулярний вираз і кожен придумує різний набір ієрогліфіків для однієї проблеми ). :)
Делікатеси

47
На стеці майже не вистачає відповідей, які насправді пояснюють, що відбувається. Дякую за чудове пояснення.
Сенді Гіффорд

Якщо ви спочатку використовуєте "@", я думаю, вам не потрібно уникати дужок?
ранг1

10
@ rank1 ви повинні уникати дужок. Що @ пропонує тут, це те, що вам не потрібно уникати нахилів. Так що без @ це було б як "\\ (([^)] *) \\)".
Діадістіс

Це, однак, не справляється з вкладеними групами Змінено наvar filterRegex = new Regex(Regex.Escape("(") + "([^()]*)" + Regex.Escape(")"));
Ян Ван дер Геген

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 = "Користувачем) ім'я (Продажі)"?
donetnetstep

@dotnetstep ти маєш рацію int end = s.IndexOf(")", start);. Я в черзі редагував ...
ChrisD

1
"(" .Length; краще, ніж +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(')')яка буде працювати, якщо є внутрішні дужки чи ні.
Бен


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
Ласкаво просимо до SO! Це хороша порада, але вона не повинна була розміщуватися як відповідь. Загальні поради на зразок цієї слід розміщувати як коментарі, якщо вони взагалі є. Відповідь має відповідати конкретній проблемі запитувача. Я знаю, що у вас ще недостатньо репутаційних очок для публікації коментарів, але саме тому існує поріг повторень. Коли ви трохи довше побували, ви побачите, що люди завжди рекомендують такі інструменти, як Rubular (звичайно, в коментарях). Іншими словами, ця порада може бути корисною, але не є нагальною.
Алан Мур

0

Я натрапив на це, поки шукав рішення дуже подібної реалізації.

Ось фрагмент мого фактичного коду. Починає підрядку з першого символу (індекс 0).

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

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

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

Це не відповідає тому, що просила ОП.
dicemaster

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.