ฉันจะแยกข้อความที่อยู่ระหว่างวงเล็บ (วงเล็บเหลี่ยม) ได้อย่างไร


224

ฉันมีสตริงUser name (sales)และฉันต้องการแยกข้อความระหว่างวงเล็บปีกกาฉันจะทำอย่างไร

ฉันสงสัยว่าสตริงย่อย แต่ฉันไม่สามารถหาวิธีการอ่านจนกระทั่งวงเล็บปิดความยาวของข้อความจะแตกต่างกัน


2
แสดงสิ่งที่คุณได้ลอง คุณเคยใช้นิพจน์ทั่วไปหรือไม่?
George Stocker

คำตอบ:


445

หากคุณต้องการที่จะอยู่ให้ห่างจากการแสดงออกปกติวิธีที่ง่ายที่สุดที่ฉันคิดได้คือ:

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

91
จริง ๆ แล้วสิ่งนี้ควรถูกเลือกเป็นคำตอบ
Pat Lindley

1
ไม่ใช่สัญญาเพิ่มเติมในการป้อนข้อมูลแยก ("()" 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(ฯลฯ
สเตฟาโน 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
ฉันรักเมื่อมีคนพูดว่า "วิธีง่ายๆคือใช้นิพจน์ทั่วไป" จากนั้นนำเสนอสิ่งที่มีค่าเป็นสตริงของอักษรอียิปต์โบราณที่อ่านไม่ออก (มันสนุกเป็นพิเศษเมื่อคนอื่นแนะนำ regex และแต่ละคนมากับชุดอักษรอียิปต์โบราณสำหรับปัญหาเดียวกัน ) :)
Deltics

47
มีคำตอบไม่มากพอที่จะอธิบายสิ่งที่เกิดขึ้นจริง ขอบคุณสำหรับคำอธิบายที่ยอดเยี่ยม
Sandy Gifford

หากคุณกำลังใช้ '@' ที่จุดเริ่มต้นฉันคิดว่าคุณไม่จำเป็นต้องหลบเลี่ยงวงเล็บ?
อันดับ 1

10
@ rank1 คุณต้องหลีกเลี่ยงวงเล็บ ข้อเสนอ @ ที่นี่คือคุณไม่จำเป็นต้องหลบหนีจากแบ็กสแลช ดังนั้นหากไม่มีเครื่องหมาย @ จะเป็นเช่น "\\ (([^)] *) \\)"
Diadistis

วิธีนี้ไม่สามารถจัดการกับกลุ่มที่ซ้อนกันได้ดี เปลี่ยนเป็น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 ในซับสตริงนั้นถูกต้องมากขึ้นถ้าคุณต้องการ "sales" แทน (sales)
Joze

1
Happend s = "ชื่อผู้ใช้ (การขาย)" คืออะไร?
dotnetstep

@dotnetstep int end = s.IndexOf(")", start);คุณสิทธิกำลังที่ควรจะเป็น ฉันรอคิวการแก้ไข ...
ChrisD

1
"(" .Length; ดีกว่า 1 ส่งแก้ไขนอกจากนี้ยังได้เพิ่มฟังก์ชั่น...
Ave

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 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
แน่นอนคุณควรคำนวณตำแหน่งของวงเล็บแรกเพียงครั้งเดียวเท่านั้น
Martin Brown

ในกรณีที่คุณมีวงเล็บภายในเช่นinput = "User name (sales(1))คุณอาจต้องการใช้input.LastIndexOf(')')ซึ่งจะทำงานหากมีวงเล็บภายในหรือไม่
Ben


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




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

นี่คือฟังก์ชั่นการอ่านที่ใช้งานทั่วไปที่หลีกเลี่ยงการใช้ regex:

// 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! นี่เป็นคำแนะนำที่ดี แต่ไม่ควรโพสต์เป็นคำตอบ คำแนะนำทั่วไปเช่นนี้ควรถูกโพสต์เป็นความคิดเห็นถ้าหากทั้งหมด คำตอบจะต้องแก้ไขปัญหาเฉพาะของผู้ถาม ฉันรู้ว่าคุณมีคะแนนชื่อเสียงไม่เพียงพอที่จะโพสต์ความคิดเห็นได้ แต่นี่เป็นเหตุผลว่าทำไมเกณฑ์ตัวแทนจึงมีอยู่ เมื่อคุณใช้เวลานานกว่านี้อีกเล็กน้อยคุณจะเห็นว่าผู้คนมักจะแนะนำเครื่องมือเช่นรูบรอล (แน่นอนในความคิดเห็น) กล่าวอีกนัยหนึ่งคำแนะนำนี้อาจเป็นประโยชน์ แต่ก็ไม่เร่งด่วน
Alan Moore

0

ฉันเจอสิ่งนี้ในขณะที่ฉันกำลังมองหาวิธีการใช้งานที่คล้ายกันมาก

นี่คือตัวอย่างจากรหัสจริงของฉัน เริ่มซับสตริงจากอักขระตัวแรก (ดัชนี 0)

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

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

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

นี่ไม่ได้ตอบสิ่งที่ OP ขอไป
dicemaster

0

รหัสนี้เร็วกว่าโซลูชันส่วนใหญ่ที่นี่ (หากไม่ใช่ทั้งหมด) ซึ่งบรรจุเป็นวิธีส่วนขยายของสตริง จะไม่สนับสนุนการทำซ้ำแบบเรียกซ้ำ:

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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.