Extrahování podřetězců z řetězce

Tento článek popisuje některé různé techniky extrakce částí řetězce.

  • Použijte metodu Split, když jsou podřetězce, které chcete získat, odděleny známým znakem oddělovače (nebo znaky).
  • Regulární výrazy jsou užitečné, když řetězec odpovídá pevnému vzoru.
  • Metody IndexOf a Substring použijte ve spojení, pokud nechcete extrahovat všechny podřetězce v řetězci.
  • Pomocí rozsahů a indexů v jazyce C# můžete extrahovat nebo oříznout znaky na známých pozicích.

Metoda String.Split

String.Split poskytuje několik přetížených funkcí, které vám pomohou rozdělit řetězec do skupiny podřetězců na základě jednoho nebo více zadaných oddělovacích znaků. Můžete se rozhodnout omezit celkový počet podřetězců v konečném výsledku, oříznout prázdné znaky z podřetězců nebo vyloučit prázdné podřetězce.

Následující příklady ukazují tři různé přetížení String.Split(). První příklad volá Split(Char[]) přetížení bez předání oddělovacích znaků. Pokud nezadáte žádné oddělovače, String.Split() rozdělí řetězec pomocí výchozích oddělovačů, což jsou prázdné znaky.

string s = "You win some. You lose some.";

string[] subs = s.Split();

foreach (string sub in subs)
{
    Console.WriteLine($"Substring: {sub}");
}

// This example produces the following output:
//
// Substring: You
// Substring: win
// Substring: some.
// Substring: You
// Substring: lose
// Substring: some.
Dim s As String = "You win some. You lose some."
Dim subs As String() = s.Split()

For Each substring As String In subs
    Console.WriteLine("Substring: {0}", substring)
Next

' This example produces the following output:
'
' Substring: You
' Substring: win
' Substring: some.
' Substring: You
' Substring: lose
' Substring: some.

Jak vidíte, znaky tečky (.) jsou zahrnuty do dvou podřetěžců. Pokud chcete znaky tečky vyloučit, můžete ho přidat jako další znak oddělovače. Další příklad ukazuje, jak to udělat.

string s = "You win some. You lose some.";

string[] subs = s.Split(' ', '.');

foreach (string sub in subs)
{
    Console.WriteLine($"Substring: {sub}");
}

// This example produces the following output:
//
// Substring: You
// Substring: win
// Substring: some
// Substring:
// Substring: You
// Substring: lose
// Substring: some
// Substring:
Dim s As String = "You win some. You lose some."
Dim subs As String() = s.Split(" "c, "."c)

For Each substring As String In subs
    Console.WriteLine("Substring: {0}", substring)
Next

' This example produces the following output:
'
' Substring: You
' Substring: win
' Substring: some
' Substring:
' Substring: You
' Substring: lose
' Substring: some
' Substring:

Tečky jsou pryč z podřetězců, ale nyní byly zahrnuty dva navíc prázdné podřetězce. Tento prázdný podřetězec představuje podřetězec mezi slovem a tečkou, která za ním následuje. Chcete-li vynechat prázdné podřetězce z výsledného pole, můžete volat přetížení Split(Char[], StringSplitOptions) a určit pro parametr StringSplitOptions.RemoveEmptyEntries hodnotu options.

string s = "You win some. You lose some.";
char[] separators = new char[] { ' ', '.' };

string[] subs = s.Split(separators, StringSplitOptions.RemoveEmptyEntries);

foreach (string sub in subs)
{
    Console.WriteLine($"Substring: {sub}");
}

// This example produces the following output:
//
// Substring: You
// Substring: win
// Substring: some
// Substring: You
// Substring: lose
// Substring: some
Dim s As String = "You win some. You lose some."
Dim separators As Char() = New Char() {" "c, "."c}
Dim subs As String() = s.Split(separators, StringSplitOptions.RemoveEmptyEntries)

For Each substring As String In subs
    Console.WriteLine("Substring: {0}", substring)
Next

' This example produces the following output:
'
' Substring: You
' Substring: win
' Substring: some
' Substring: You
' Substring: lose
' Substring: some

Regulární výrazy

Pokud je řetězec v souladu s pevným vzorem, můžete k extrakci a zpracování jeho prvků použít regulární výraz. Pokud mají řetězce tvar "číslooperandčíslo", můžete k extrakci a zpracování prvků řetězce použít regulární výraz. Tady je příklad:

String[] expressions = { "16 + 21", "31 * 3", "28 / 3",
                       "42 - 18", "12 * 7",
                       "2, 4, 6, 8" };
String pattern = @"(\d+)\s+([-+*/])\s+(\d+)";

foreach (string expression in expressions)
{
    foreach (System.Text.RegularExpressions.Match m in
    System.Text.RegularExpressions.Regex.Matches(expression, pattern))
    {
        int value1 = Int32.Parse(m.Groups[1].Value);
        int value2 = Int32.Parse(m.Groups[3].Value);
        switch (m.Groups[2].Value)
        {
            case "+":
                Console.WriteLine($"{m.Value} = {value1 + value2}");
                break;
            case "-":
                Console.WriteLine($"{m.Value} = {value1 - value2}");
                break;
            case "*":
                Console.WriteLine($"{m.Value} = {value1 * value2}");
                break;
            case "/":
                Console.WriteLine($"{m.Value} = {value1 / value2:N2}");
                break;
        }
    }
}

// The example displays the following output:
//       16 + 21 = 37
//       31 * 3 = 93
//       28 / 3 = 9.33
//       42 - 18 = 24
//       12 * 7 = 84
Dim expressions() As String = {"16 + 21", "31 * 3", "28 / 3",
                              "42 - 18", "12 * 7",
                              "2, 4, 6, 8"}

Dim pattern As String = "(\d+)\s+([-+*/])\s+(\d+)"
For Each expression In expressions
    For Each m As Match In Regex.Matches(expression, pattern)
        Dim value1 As Integer = Int32.Parse(m.Groups(1).Value)
        Dim value2 As Integer = Int32.Parse(m.Groups(3).Value)
        Select Case m.Groups(2).Value
            Case "+"
                Console.WriteLine("{0} = {1}", m.Value, value1 + value2)
            Case "-"
                Console.WriteLine("{0} = {1}", m.Value, value1 - value2)
            Case "*"
                Console.WriteLine("{0} = {1}", m.Value, value1 * value2)
            Case "/"
                Console.WriteLine("{0} = {1:N2}", m.Value, value1 / value2)
        End Select
    Next
Next

' The example displays the following output:
'       16 + 21 = 37
'       31 * 3 = 93
'       28 / 3 = 9.33
'       42 - 18 = 24
'       12 * 7 = 84

Vzor regulárního výrazu (\d+)\s+([-+*/])\s+(\d+) je definován takto:

Vzor Popis
(\d+) Porovná jednu nebo více desítkových číslic. Toto je první zachytávající skupina.
\s+ Odpovídá jednomu nebo více bílým znakům.
([-+*/]) Porovná znaménko aritmetického operátoru (+, -, *nebo /). Toto je druhá zachytávající skupina.
\s+ Odpovídá jednomu nebo více bílým znakům.
(\d+) Porovná jednu nebo více desítkových číslic. Toto je třetí zachytávající skupina.

Regulární výraz můžete použít také k extrakci podřetězců z řetězce založeného na vzoru místo pevné sady znaků. Jedná se o běžný scénář, kdy dojde k některé z těchto podmínek:

  • Jeden nebo více znaků oddělovače nemusí vždy sloužit jako oddělovač String v instanci.

  • Posloupnost a počet oddělovačových znaků jsou proměnné nebo neznámé.

Například metodu Split nelze použít k rozdělení následujícího řetězce, protože počet \n znaků (newline) je proměnný a nemusí vždy sloužit jako oddělovače.

[This is captured\ntext.]\n\n[\n[This is more captured text.]\n]
\n[Some more captured text:\n   Option1\n   Option2][Terse text.]

Regulární výraz může tento řetězec snadno rozdělit, jak ukazuje následující příklad.

String input = "[This is captured\ntext.]\n\n[\n" +
               "[This is more captured text.]\n]\n" +
               "[Some more captured text:\n   Option1" +
               "\n   Option2][Terse text.]";
String pattern = @"\[([^\[\]]+)\]";
int ctr = 0;

foreach (System.Text.RegularExpressions.Match m in
   System.Text.RegularExpressions.Regex.Matches(input, pattern))
{
    Console.WriteLine($"{++ctr}: {m.Groups[1].Value}");
}

// The example displays the following output:
//       1: This is captured
//       text.
//       2: This is more captured text.
//       3: Some more captured text:
//          Option1
//          Option2
//       4: Terse text.
Dim input As String = String.Format("[This is captured{0}text.]" +
                                  "{0}{0}[{0}[This is more " +
                                  "captured text.]{0}{0}" +
                                  "[Some more captured text:" +
                                  "{0}   Option1" +
                                  "{0}   Option2][Terse text.]",
                                  vbCrLf)
Dim pattern As String = "\[([^\[\]]+)\]"
Dim ctr As Integer = 0
For Each m As Match In Regex.Matches(input, pattern)
    ctr += 1
    Console.WriteLine("{0}: {1}", ctr, m.Groups(1).Value)
Next

' The example displays the following output:
'       1: This is captured
'       text.
'       2: This is more captured text.
'       3: Some more captured text:
'          Option1
'          Option2
'       4: Terse text.

Vzor regulárního výrazu \[([^\[\]]+)\] je definován takto:

Vzor Popis
\[ Přiřaďte otevírací závorku.
([^\[\]]+) Porovná libovolný znak, který není levou nebo pravou závorkou jednou nebo vícekrát. Toto je první zachytávající skupina.
\] Spárujte uzavírací závorku.

Metoda Regex.Split je téměř identická s String.Splittím rozdílem, že rozdělí řetězec na základě vzoru regulárního výrazu místo pevné znakové sady. Například následující příklad používá metodu Regex.Split k rozdělení řetězce, který obsahuje podřetězce oddělené různými kombinacemi spojovníků a dalších znaků.

String input = "abacus -- alabaster - * - atrium -+- " +
               "any -*- actual - + - armoire - - alarm";
String pattern = @"\s-\s?[+*]?\s?-\s";
String[] elements = System.Text.RegularExpressions.Regex.Split(input, pattern);

foreach (string element in elements)
    Console.WriteLine(element);

// The example displays the following output:
//       abacus
//       alabaster
//       atrium
//       any
//       actual
//       armoire
//       alarm
Dim input As String = "abacus -- alabaster - * - atrium -+- " +
                    "any -*- actual - + - armoire - - alarm"
Dim pattern As String = "\s-\s?[+*]?\s?-\s"
Dim elements() As String = Regex.Split(input, pattern)
For Each element In elements
    Console.WriteLine(element)
Next

' The example displays the following output:
'       abacus
'       alabaster
'       atrium
'       any
'       actual
'       armoire
'       alarm

Vzor regulárního výrazu \s-\s?[+*]?\s?-\s je definován takto:

Vzor Popis
\s- Porovná prázdný znak následovaný pomlčkou.
\s? Porovná žádný nebo jeden prázdný znak.
[+*]? Porovná žádný nebo jeden výskyt znaku + nebo *.
\s? Porovná žádný nebo jeden prázdný znak.
-\s Najdi spojovník následovaný mezerou.

Metody String.IndexOf a String.Substring

Pokud vás všechny podřetězce v řetězci nezajímají, můžete raději pracovat s některou z metod porovnání řetězců, která vrátí index, na kterém začíná shoda. Potom můžete volat metodu Substring pro extrahování požadovaného podřetězce. Mezi metody porovnání řetězců patří:

  • IndexOf, který vrací index začínající na nule pro první výskyt znaku nebo řetězce v rámci řetězce.

  • IndexOfAny, který vrátí index založený na nule v aktuální řetězcové instanci prvního výskytu libovolného znaku v poli znaků.

  • LastIndexOf, který vrátí index založený na nule posledního výskytu znaku nebo řetězce v instanci řetězce.

  • LastIndexOfAny, který vrátí index založený na nule v aktuální řetězcové instanci posledního výskytu libovolného znaku v poli znaků.

Následující příklad používá metodu IndexOf k vyhledání období v řetězci. Pak použije metodu Substring k vrácení celých vět.

String s = "This is the first sentence in a string. " +
               "More sentences will follow. For example, " +
               "this is the third sentence. This is the " +
               "fourth. And this is the fifth and final " +
               "sentence.";
var sentences = new List<String>();
int start = 0;
int position;

// Extract sentences from the string.
do
{
    position = s.IndexOf('.', start);
    if (position >= 0)
    {
        sentences.Add(s.Substring(start, position - start + 1).Trim());
        start = position + 1;
    }
} while (position > 0);

// Display the sentences.
foreach (var sentence in sentences)
    Console.WriteLine(sentence);

// The example displays the following output:
//       This is the first sentence in a string.
//       More sentences will follow.
//       For example, this is the third sentence.
//       This is the fourth.
//       And this is the fifth and final sentence.
    Dim input As String = "This is the first sentence in a string. " +
                        "More sentences will follow. For example, " +
                        "this is the third sentence. This is the " +
                        "fourth. And this is the fifth and final " +
                        "sentence."
    Dim sentences As New List(Of String)
    Dim start As Integer = 0
    Dim position As Integer

    ' Extract sentences from the string.
    Do
        position = input.IndexOf("."c, start)
        If position >= 0 Then
            sentences.Add(input.Substring(start, position - start + 1).Trim())
            start = position + 1
        End If
    Loop While position > 0

    ' Display the sentences.
    For Each sentence In sentences
        Console.WriteLine(sentence)
    Next
End Sub

' The example displays the following output:
'       This is the first sentence in a string.
'       More sentences will follow.
'       For example, this is the third sentence.
'       This is the fourth.
'       And this is the fifth and final sentence.

Rozsahy a indexy

Operátor rozsahu v C# a operátor indexu od konce umožňují extrahovat podřetězce pomocí stručné syntaxe. Tyto operátory můžete použít přímo na řetězce bez volání Substring.

Následující příklad ukazuje několik způsobů, jak extrahovat části řetězce pomocí rozsahů:

string str = "Hello, World!";

// Get the first 5 characters.
string hello = str[..5];
Console.WriteLine(hello);
// Output: Hello

// Get the last 6 characters.
string world = str[^6..];
Console.WriteLine(world);
// Output: World!

// Get characters from index 7 through 11 (exclusive of 12).
string substr = str[7..12];
Console.WriteLine(substr);
// Output: World

V dalším příkladu se pomocí operátoru index-from-end odebere přípona souboru (poslední tři znaky) z cesty:

string filePath = "C:\\Users\\user1\\bin\\fileA.cs";

// Remove the last 3 characters (.cs extension).
string trimmedPath = filePath[..^3];
Console.WriteLine(trimmedPath);
// Output: C:\Users\user1\bin\fileA

Poznámka:

Rozsahy a operátor „index-from-end“ jsou vlastnosti jazyka C#. Visual Basic tuto syntaxi nepodporuje; místo toho použijte Substring .

Viz také