Estrarre sottostringhe da una stringa

Questo articolo illustra alcune tecniche diverse per estrarre parti di una stringa.

  • Utilizzare il metodo Split quando le sottostringhe sono separate da uno o più caratteri di delimitazione noti.
  • Le espressioni regolari sono utili quando la stringa è conforme a un criterio fisso.
  • Usare i metodi IndexOf e Substring insieme quando non si desidera estrarre tutte le sottostringhe di una stringa.

Metodo String.Split

String.Split fornisce alcuni overload che consentono di suddividere una stringa in un gruppo di sottostringhe in base a uno o più caratteri delimitatori specificati. È possibile scegliere di limitare il numero totale di sottostringhe nel risultato finale, tagliare gli spazi vuoti dalle sottostringhe o escludere le sottostringhe vuote.

Gli esempi seguenti illustrano tre diversi overload di String.Split(). Il primo esempio chiama l'overload Split(Char[]) senza passare caratteri separatori. Se non si specificano caratteri di delimitazione, String.Split() usa i delimitatori predefiniti, ovvero spazi vuoti, per dividere la stringa.

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.

Come si può notare, i caratteri punto (.) sono inclusi in due delle sottostringhe. Se si vogliono escludere i caratteri punto, è possibile aggiungere il punto come delimitatore aggiuntivo. L'esempio successivo illustra come effettuare questa operazione.

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:

I punti sono stati rimossi dalle sottostringhe, ma sono state incluse due sottostringhe aggiuntive vuote. Queste sottostringhe vuote rappresentano la sottostringa tra la parola e il punto che la segue. Per omettere le sottostringhe vuote dalla matrice risultante, è possibile chiamare l'overload Split(Char[], StringSplitOptions) e specificare StringSplitOptions.RemoveEmptyEntries per il parametro 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

Espressioni regolari

Se la stringa è conforme a un criterio fisso, è possibile usare un'espressione regolare per estrarre e gestire i relativi elementi. Ad esempio, se le stringhe accettano il formato "numero operandonumero", è possibile usare un'espressione regolare per estrarre e gestire i relativi elementi. Ecco un esempio:

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("{0} = {1}", m.Value, value1 + value2);
                break;
            case "-":
                Console.WriteLine("{0} = {1}", m.Value, value1 - value2);
                break;
            case "*":
                Console.WriteLine("{0} = {1}", m.Value, value1 * value2);
                break;
            case "/":
                Console.WriteLine("{0} = {1:N2}", m.Value, value1 / value2);
                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

Il criterio (\d+)\s+([-+*/])\s+(\d+) dell'espressione regolare viene definito in questo modo:

Modello Descrizione
(\d+) Trova la corrispondenza con una o più cifre decimali. Equivale al primo gruppo di acquisizione.
\s+ Trova uno o più spazi vuoti.
([-+*/]) Trova un segno di operatore aritmetico (+, -, *o /). Equivale al secondo gruppo di acquisizione.
\s+ Trova uno o più spazi vuoti.
(\d+) Trova la corrispondenza con una o più cifre decimali. Equivale al terzo gruppo di acquisizione.

È anche possibile usare un'espressione regolare per estrarre sottostringhe da una stringa in base a un criterio anziché a un set fisso di caratteri. Questo scenario è comune quando si verifica una di queste condizioni:

  • Uno o più caratteri delimitatori non fungono sempre da delimitatori nell'istanza di String.

  • La sequenza e il numero di caratteri delimitatori sono variabili o sconosciuti.

Ad esempio, il metodo Split non può essere usato per dividere la stringa seguente, perché i caratteri \n (nuova riga) sono in numero variabile e non sempre fungono da delimitatori.

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

Un'espressione regolare può dividere facilmente questa stringa, come illustrato nell'esempio seguente.

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("{0}: {1}", ++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.

Il criterio \[([^\[\]]+)\] dell'espressione regolare viene definito in questo modo:

Modello Descrizione
\[ Trova una parentesi quadra aperta.
([^\[\]]+) Trova una o più volte qualsiasi carattere diverso da una parentesi quadra aperta o chiusa. Equivale al primo gruppo di acquisizione.
\] Trova una parentesi quadra chiusa.

Il metodo Regex.Split è quasi identico a String.Split, ad eccezione del fatto che divide una stringa in base a un criterio di espressione regolare anziché a un set di caratteri fisso. Nell'esempio seguente viene utilizzato il metodo Regex.Split per dividere una stringa contenente sottostringhe delimitate da varie combinazioni di trattini e altri caratteri.

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

Il criterio \s-\s?[+*]?\s?-\s dell'espressione regolare viene definito in questo modo:

Modello Descrizione
\s- Trova uno spazio vuoto seguito da un trattino.
\s? Trova la corrispondenza di uno o nessuno spazio vuoto.
[+*]? Trova zero o una occorrenza del carattere + o *.
\s? Trova la corrispondenza di uno o nessuno spazio vuoto.
-\s Trova un trattino seguito da uno spazio vuoto.

Metodi String.IndexOf e String.Substring

Se non si è interessati a tutte le sottostringhe di una stringa, è consigliabile usare uno dei metodi di confronto tra stringhe che restituisce l'indice in corrispondenza del quale inizia la corrispondenza. È quindi possibile chiamare il metodo Substring per estrarre la sottostringa desiderata. I metodi di confronto tra stringhe includono:

  • IndexOf, che restituisce l'indice in base zero della prima occorrenza di un carattere o di una stringa in un'istanza di stringa.

  • IndexOfAny, che restituisce l'indice in base zero della prima occorrenza di qualsiasi carattere di una matrice di caratteri nell'istanza di stringa corrente.

  • LastIndexOf, che restituisce l'indice in base zero dell'ultima occorrenza di un carattere o di una stringa in un'istanza di stringa.

  • LastIndexOfAny, che restituisce l'indice in base zero dell'ultima occorrenza di qualsiasi carattere di una matrice di caratteri nell'istanza di stringa corrente.

L'esempio seguente usa il metodo IndexOf per trovare i punti in una stringa. Usa quindi il metodo Substring per restituire frasi complete.

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.

Vedi anche