Share via


Detail perilaku regex

Mesin regex .NET adalah pencocokan regex backtracking yang menggabungkan mesin Nondeterministic Finite Automaton (NFA) tradisional seperti yang digunakan oleh Perl, Python, Emacs, dan Tcl. Ini membedakannya dari mesin Deterministic Finite Automaton (DFA) regex murni yang lebih cepat, tetapi lebih terbatas, seperti yang ditemukan dalam awk, egrep, atau lex. Ini juga membedakannya dari NFAs POSIX yang standar, tetapi lebih lambat. Bagian berikut mendeskripsikan tiga jenis mesin regex dan menjelaskan mengapa regex di .NET diimplementasikan dengan menggunakan mesin NFA tradisional.

Manfaat mesin NFA

Saat mesin DFA melakukan pencocokan pola, urutan pemrosesannya didorong oleh string input. Mesin dimulai pada awal string input dan melanjutkan secara berurutan untuk menentukan apakah karakter berikutnya cocok dengan pola regex. Mereka dapat menjamin untuk mencocokkan string terpanjang yang mungkin terjadi. Karena mereka tidak pernah menguji karakter yang sama dua kali, mesin DFA tidak mendukung backtracking. Namun, mesin DFA tidak dapat mencocokkan pola dengan backreference karena hanya berisi status terbatas dan tidak dapat mengambil subekspresi karena tidak membangun ekspansi eksplisit.

Tidak seperti mesin DFA, saat mesin NFA tradisional melakukan pencocokan pola, urutan pemrosesannya didorong oleh pola regex. Saat memproses elemen bahasa tertentu, mesin menggunakan pencocokan serakah; artinya, cocok dengan sebanyak apa pun string input. Tetapi demikian juga menyimpan statusnya setelah berhasil mencocokkan subekspresi. Jika pencocokan akhirnya gagal, mesin dapat kembali ke status tersimpan sehingga dapat mencoba pencocokan tambahan. Proses ini mengabaikan pencocokan subekspresi yang berhasil, sehingga elemen bahasa nantinya dalam regex juga dapat cocok dan dikenal sebagai backtracking. Mesin NFA menggunakan backtracking untuk menguji semua kemungkinan ekspansi regex dalam urutan tertentu dan menerima pencocokan pertama. Karena mesin NFA tradisional membuat ekspansi tertentu dari regex untuk pencocokan yang sukses, mesin ini dapat menangkap pencocokan subekspresi dan backreference yang cocok. Namun, karena backtrack NFA tradisional, mesin ini dapat mengunjungi status yang sama beberapa kali jika tiba di status tersebut melalui jalur yang berbeda. Akibatnya, mesin ini dapat berjalan lambat secara eksponensial dalam kasus terburuk. Karena mesin NFA tradisional menerima pencocokan pertama yang ditemukannya, mesin tersebut juga dapat meninggalkan pencocokan lain (mungkin lebih lama) yang belum ditemukan.

Mesin NFA POSIX seperti mesin NFA tradisional, kecuali mereka terus melakukan backtrack sampai mereka dapat menjamin bahwa mereka telah menemukan pencocokan terpanjang yang mungkin terjadi. Akibatnya, mesin NFA POSIX lebih lambat daripada mesin NFA tradisional dan saat Anda menggunakan mesin NFA POSIX, Anda tidak dapat memilih pencocokan yang lebih pendek daripada yang lebih lama dengan mengubah urutan pencarian backtracking.

Mesin NFA tradisional dipilih oleh pemrogram karena menawarkan kontrol yang lebih besar atas pencocokan string daripada mesin NFA DFA atau POSIX. Meskipun, dalam kasus terburuk, mereka dapat berjalan lambat, Anda dapat mengarahkannya untuk menemukan kecocokan dalam waktu linier atau polinomial dengan menggunakan pola yang mengurangi ambiguitas dan membatasi backtracking. Dengan kata lain, meskipun mesin NFA menukar performa untuk daya dan fleksibilitas, dalam sebagian besar kasus mereka menawarkan performa yang baik dan dapat diterima jika regex ditulis dengan baik dan menghindari kasus di mana backtracking menurunkan performa secara eksponensial.

Catatan

Untuk informasi tentang penalti performa yang disebabkan oleh backtracking yang berlebihan dan cara membuat regex untuk mengatasinya, lihat Backtracking.

Kemampuan mesin .NET

Untuk mengambil keuntungan dari manfaat mesin NFA tradisional, mesin regex .NET mencakup serangkaian konstruksi lengkap untuk memungkinkan pemrogram mengarahkan mesin backtracking. Konstruksi ini dapat digunakan untuk menemukan kecocokan dengan lebih cepat atau memilih ekspansi tertentu daripada yang lainnya.

Fitur lain dari mesin regex .NET meliputi:

  • Kuantifer malas: ??, *?, +?, {n,m}?. Konstruksi ini memberi tahu mesin backtracking untuk mencari jumlah minimum dari pengulangan terlebih dahulu. Sebaliknya, kuantifer serakah biasa mencoba mencocokkan jumlah maksimum dari pengulangan terlebih dahulu. Contoh berikut menggambarkan perbedaan di antara keduanya. Regex cocok dengan kalimat yang diakhiri dengan angka, dan grup penangkapan dimaksudkan untuk mengekstrak angka tersebut. Regex .+(\d+)\. mencakup kuantifer serakah .+, yang menyebabkan mesin regex hanya mengambil digit terakhir dari angka tersebut. Sebaliknya, regex .+?(\d+)\. mencakup kuantifer malas .+?, yang menyebabkan mesin regex mengambil seluruh angka.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string greedyPattern = @".+(\d+)\.";
            string lazyPattern = @".+?(\d+)\.";
            string input = "This sentence ends with the number 107325.";
            Match match;
    
            // Match using greedy quantifier .+.
            match = Regex.Match(input, greedyPattern);
            if (match.Success)
                Console.WriteLine("Number at end of sentence (greedy): {0}",
                                  match.Groups[1].Value);
            else
                Console.WriteLine("{0} finds no match.", greedyPattern);
    
            // Match using lazy quantifier .+?.
            match = Regex.Match(input, lazyPattern);
            if (match.Success)
                Console.WriteLine("Number at end of sentence (lazy): {0}",
                                  match.Groups[1].Value);
            else
                Console.WriteLine("{0} finds no match.", lazyPattern);
        }
    }
    // The example displays the following output:
    //       Number at end of sentence (greedy): 5
    //       Number at end of sentence (lazy): 107325
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim greedyPattern As String = ".+(\d+)\."
            Dim lazyPattern As String = ".+?(\d+)\."
            Dim input As String = "This sentence ends with the number 107325."
            Dim match As Match
    
            ' Match using greedy quantifier .+.
            match = Regex.Match(input, greedyPattern)
            If match.Success Then
                Console.WriteLine("Number at end of sentence (greedy): {0}",
                                  match.Groups(1).Value)
            Else
                Console.WriteLine("{0} finds no match.", greedyPattern)
            End If
    
            ' Match using lazy quantifier .+?.
            match = Regex.Match(input, lazyPattern)
            If match.Success Then
                Console.WriteLine("Number at end of sentence (lazy): {0}",
                                  match.Groups(1).Value)
            Else
                Console.WriteLine("{0} finds no match.", lazyPattern)
            End If
        End Sub
    End Module
    ' The example displays the following output:
    '       Number at end of sentence (greedy): 5
    '       Number at end of sentence (lazy): 107325
    

    Versi serakah dan malas dari regex ini didefinisikan seperti yang ditunjukkan dalam tabel berikut:

    Pola Deskripsi
    .+ (kuintifer serakah) Cocokkan setidaknya satu kemunculan dari karakter apa pun. Hal ini menyebabkan mesin regex mencocokkan seluruh string, lalu melakukan backtrack sesuai kebutuhan untuk mencocokkan sisa pola.
    .+? (kuantifer malas) Cocokkan setidaknya satu kemunculan dari karakter apa pun, tetapi cocokkan sesedikit mungkin.
    (\d+) Cocokkan setidaknya satu karakter numerik dan tetapkan pada grup penangkapan pertama.
    \. Cocokkan tanda titik.

    Untuk informasi selengkapnya tentang kuantifer malas, lihat Kuantifer.

  • Lookahead positif: (?=subekspresi). Fitur ini memungkinkan mesin backtracking untuk kembali ke tempat yang sama dalam teks setelah mencocokkan subekspresi. Ini berguna untuk mencari di seluruh teks dengan memverifikasi beberapa pola yang dimulai dari posisi yang sama. Ini juga memungkinkan mesin untuk memverifikasi bahwa substring ada di akhir pencocokan tanpa menyertakan substring dalam teks yang cocok. Contoh berikut menggunakan lookahead positif untuk mengekstrak kata-kata dalam kalimat yang tidak diikuti dengan simbol tanda baca.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string pattern = @"\b[A-Z]+\b(?=\P{P})";
            string input = "If so, what comes next?";
            foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
                Console.WriteLine(match.Value);
        }
    }
    // The example displays the following output:
    //       If
    //       what
    //       comes
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim pattern As String = "\b[A-Z]+\b(?=\P{P})"
            Dim input As String = "If so, what comes next?"
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
                Console.WriteLine(match.Value)
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '       If
    '       what
    '       comes
    

    Regex \b[A-Z]+\b(?=\P{P}) didefinisikan seperti yang ditunjukkan pada tabel berikut.

    Pola Deskripsi
    \b Memulai pencocokan dalam batas kata.
    [A-Z]+ Cocokkan karakter alfabet apa pun satu kali atau lebih. Karena metode Regex.Matches dipanggil dengan opsi RegexOptions.IgnoreCase, perbandingannya tidak peka terhadap huruf besar/kecil.
    \b Mengakhiri pencocokan dalam batas kata.
    (?=\P{P}) Lihatlah ke depan untuk menentukan apakah karakter berikutnya adalah simbol tanda baca. Jika tidak, pencocokan berhasil.

    Untuk informasi selengkapnya tentang pernyataan lookahead positif, lihat Konstruksi Pengelompokan.

  • Lookahead negatif: (?!subekspresi). Fitur ini menambahkan kemampuan untuk mencocokkan ekspresi hanya jika subekspresi gagal dicocokkan. Ini sangat berguna untuk memangkas pencarian, karena sering kali lebih sederhana untuk memberikan ekspresi bagi kasus yang harus dihilangkan daripada ekspresi bagi kasus yang harus disertakan. Misalnya, sulit untuk menulis ekspresi bagi kata-kata yang tidak dimulai dengan "non". Contoh berikut menggunakan lookahead negatif untuk mengecualikannya.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string pattern = @"\b(?!non)\w+\b";
            string input = "Nonsense is not always non-functional.";
            foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
                Console.WriteLine(match.Value);
        }
    }
    // The example displays the following output:
    //       is
    //       not
    //       always
    //       functional
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim pattern As String = "\b(?!non)\w+\b"
            Dim input As String = "Nonsense is not always non-functional."
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
                Console.WriteLine(match.Value)
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '       is
    '       not
    '       always
    '       functional
    

    Pola regex \b(?!non)\w+\b didefinisikan seperti yang ditunjukkan pada tabel berikut.

    Pola Deskripsi
    \b Memulai pencocokan dalam batas kata.
    (?!non) Lihatlah ke depan untuk memastikan bahwa string saat ini tidak dimulai dengan "non". Jika ya, pencocokan gagal.
    (\w+) Mencocokkan satu atau beberapa karakter kata.
    \b Mengakhiri pencocokan dalam batas kata.

    Untuk informasi selengkapnya tentang pernyataan lookahead negatif, lihat Konstruksi Pengelompokan.

  • Evaluasi kondisional: (?(ekspresi)ya|tidak) dan (?(nama)ya|tidak), di mana ekspresi adalah subekspresi yang cocok, nama adalah nama grup penangkapan, ya adalah string yang cocok jika ekspresi cocok atau nama adalah grup terambil yang valid dan tidak kosong, dan tidak adalah subekspresi yang cocok jika ekspresi tidak cocok atau nama bukan grup terambil yang valid dan tidak kosong. Fitur ini memungkinkan mesin untuk mencari dengan menggunakan lebih dari satu pola alternatif, tergantung pada hasil pencocokan subekspresi sebelumnya atau hasil pernyataan dengan lebar-nol. Ini memungkinkan bentuk backreference yang lebih kuat yang memungkinkan, misalnya, mencocokkan subekspresi berdasarkan apakah subekspresi sebelumnya cocok. Regex dalam contoh berikut cocok dengan paragraf yang ditujukan untuk penggunaan publik dan internal. Paragraf hanya ditujukan untuk penggunaan internal yang dimulai dengan tag <PRIVATE>. Pola regex ^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$ menggunakan evaluasi kondisional untuk menetapkan konten paragraf yang ditujukan untuk penggunaan publik dan internal guna memisahkan grup penangkapan. Paragraf ini kemudian dapat dihandel secara berbeda.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string input = "<PRIVATE> This is not for public consumption." + Environment.NewLine +
                           "But this is for public consumption." + Environment.NewLine +
                           "<PRIVATE> Again, this is confidential.\n";
            string pattern = @"^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$";
            string publicDocument = null, privateDocument = null;
    
            foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Multiline))
            {
                if (match.Groups[1].Success)
                {
                    privateDocument += match.Groups[1].Value + "\n";
                }
                else
                {
                    publicDocument += match.Groups[3].Value + "\n";
                    privateDocument += match.Groups[3].Value + "\n";
                }
            }
    
            Console.WriteLine("Private Document:");
            Console.WriteLine(privateDocument);
            Console.WriteLine("Public Document:");
            Console.WriteLine(publicDocument);
        }
    }
    // The example displays the following output:
    //    Private Document:
    //    This is not for public consumption.
    //    But this is for public consumption.
    //    Again, this is confidential.
    //
    //    Public Document:
    //    But this is for public consumption.
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim input As String = "<PRIVATE> This is not for public consumption." + vbCrLf + _
                                  "But this is for public consumption." + vbCrLf + _
                                  "<PRIVATE> Again, this is confidential." + vbCrLf
            Dim pattern As String = "^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$"
            Dim publicDocument As String = Nothing
            Dim privateDocument As String = Nothing
    
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.Multiline)
                If match.Groups(1).Success Then
                    privateDocument += match.Groups(1).Value + vbCrLf
                Else
                    publicDocument += match.Groups(3).Value + vbCrLf
                    privateDocument += match.Groups(3).Value + vbCrLf
                End If
            Next
    
            Console.WriteLine("Private Document:")
            Console.WriteLine(privateDocument)
            Console.WriteLine("Public Document:")
            Console.WriteLine(publicDocument)
        End Sub
    End Module
    ' The example displays the following output:
    '    Private Document:
    '    This is not for public consumption.
    '    But this is for public consumption.
    '    Again, this is confidential.
    '    
    '    Public Document:
    '    But this is for public consumption.
    

    Pola regex didefinisikan seperti yang ditunjukkan pada tabel berikut.

    Pola Deskripsi
    ^ Mulailah pencocokan pada awal baris.
    (?<Pvt>\<PRIVATE\>\s)? Cocokkan nol atau satu kemunculan string <PRIVATE> diikuti dengan karakter spasi putih. Tetapkan kecocokan pada grup penangkapan bernama Pvt.
    (?(Pvt)((\w+\p{P}?\s)+) Jika grup penangkapan Pvt ada, cocokkan satu atau beberapa kemunculan dari satu atau beberapa karakter kata diikuti dengan nol atau satu pemisah tanda baca diikuti dengan karakter spasi putih. Tetapkan substring pada grup penangkapan pertama.
    |((\w+\p{P}?\s)+)) Jika grup penangkapan Pvt tidak ada, cocokkan satu atau beberapa kemunculan dari satu atau beberapa karakter kata diikuti dengan nol atau satu pemisah tanda baca diikuti dengan karakter spasi putih. Tetapkan substring pada grup penangkapan ketiga.
    \r?$ Cocokkan akhir baris atau akhir string.

    Untuk informasi selengkapnya tentang evaluasi kondisional, lihat Konstruksi Perubahan.

  • Menyeimbangkan definisi grup: (?<nama1-nama2>subekspresi). Fitur ini memungkinkan mesin regex untuk melacak konstruksi berlapis, seperti tanda kurung atau kurung buka dan tutup. Misalnya, lihat Konstruksi Pengelompokan.

  • Grup atom: (?>subekspresi). Fitur ini memungkinkan mesin backtracking untuk menjamin bahwa subekspresi hanya cocok dengan pencocokan pertama yang ditemukan untuk subekspresi tersebut, seolah-olah ekspresi berjalan secara independen dari ekspresi yang memuatnya. Jika Anda tidak menggunakan konstruksi ini, pencarian backtracking dari ekspresi yang lebih besar dapat mengubah perilaku subekspresi. Misalnya, regex (a+)\w cocok dengan satu atau beberapa karakter "a", bersama dengan karakter kata yang mengikuti urutan karakter "a" dan menetapkan urutan karakter "a" ke grup penangkapan pertama. Namun, jika karakter akhir dari string input juga merupakan "a", karakter tersebut dicocokkan dengan elemen bahasa \w dan tidak disertakan dalam grup yang diambil.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string[] inputs = { "aaaaa", "aaaaab" };
            string backtrackingPattern = @"(a+)\w";
            Match match;
    
            foreach (string input in inputs)
            {
                Console.WriteLine("Input: {0}", input);
                match = Regex.Match(input, backtrackingPattern);
                Console.WriteLine("   Pattern: {0}", backtrackingPattern);
                if (match.Success)
                {
                    Console.WriteLine("      Match: {0}", match.Value);
                    Console.WriteLine("      Group 1: {0}", match.Groups[1].Value);
                }
                else
                {
                    Console.WriteLine("      Match failed.");
                }
            }
            Console.WriteLine();
        }
    }
    // The example displays the following output:
    //       Input: aaaaa
    //          Pattern: (a+)\w
    //             Match: aaaaa
    //             Group 1: aaaa
    //       Input: aaaaab
    //          Pattern: (a+)\w
    //             Match: aaaaab
    //             Group 1: aaaaa
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim inputs() As String = {"aaaaa", "aaaaab"}
            Dim backtrackingPattern As String = "(a+)\w"
            Dim match As Match
    
            For Each input As String In inputs
                Console.WriteLine("Input: {0}", input)
                match = Regex.Match(input, backtrackingPattern)
                Console.WriteLine("   Pattern: {0}", backtrackingPattern)
                If match.Success Then
                    Console.WriteLine("      Match: {0}", match.Value)
                    Console.WriteLine("      Group 1: {0}", match.Groups(1).Value)
                Else
                    Console.WriteLine("      Match failed.")
                End If
            Next
            Console.WriteLine()
        End Sub
    End Module
    ' The example displays the following output:
    '       Input: aaaaa
    '          Pattern: (a+)\w
    '             Match: aaaaa
    '             Group 1: aaaa
    '       Input: aaaaab
    '          Pattern: (a+)\w
    '             Match: aaaaab
    '             Group 1: aaaaa
    

    Regex ((?>a+))\w mencegah perilaku ini. Karena semua karakter "a" yang berurutan dicocokkan tanpa backtracking, grup penangkapan pertama mencakup semua karakter "a" yang berurutan. Jika karakter "a" tidak diikuti dengan setidaknya satu karakter selain "a", pencocokan gagal.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string[] inputs = { "aaaaa", "aaaaab" };
            string nonbacktrackingPattern = @"((?>a+))\w";
            Match match;
    
            foreach (string input in inputs)
            {
                Console.WriteLine("Input: {0}", input);
                match = Regex.Match(input, nonbacktrackingPattern);
                Console.WriteLine("   Pattern: {0}", nonbacktrackingPattern);
                if (match.Success)
                {
                    Console.WriteLine("      Match: {0}", match.Value);
                    Console.WriteLine("      Group 1: {0}", match.Groups[1].Value);
                }
                else
                {
                    Console.WriteLine("      Match failed.");
                }
            }
            Console.WriteLine();
        }
    }
    // The example displays the following output:
    //       Input: aaaaa
    //          Pattern: ((?>a+))\w
    //             Match failed.
    //       Input: aaaaab
    //          Pattern: ((?>a+))\w
    //             Match: aaaaab
    //             Group 1: aaaaa
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim inputs() As String = {"aaaaa", "aaaaab"}
            Dim nonbacktrackingPattern As String = "((?>a+))\w"
            Dim match As Match
    
            For Each input As String In inputs
                Console.WriteLine("Input: {0}", input)
                match = Regex.Match(input, nonbacktrackingPattern)
                Console.WriteLine("   Pattern: {0}", nonbacktrackingPattern)
                If match.Success Then
                    Console.WriteLine("      Match: {0}", match.Value)
                    Console.WriteLine("      Group 1: {0}", match.Groups(1).Value)
                Else
                    Console.WriteLine("      Match failed.")
                End If
            Next
            Console.WriteLine()
        End Sub
    End Module
    ' The example displays the following output:
    '       Input: aaaaa
    '          Pattern: ((?>a+))\w
    '             Match failed.
    '       Input: aaaaab
    '          Pattern: ((?>a+))\w
    '             Match: aaaaab
    '             Group 1: aaaaa
    

    Untuk informasi selengkapnya tentang grup atom, lihat Konstruksi Pengelompokan.

  • Pencocokan kanan-ke-kiri, yang ditentukan dengan menyediakan opsi RegexOptions.RightToLeft ke konstruktor kelas Regex atau metode pencocokan instans yang statis. Fitur ini berguna saat mencari dari kanan ke kiri alih-alih dari kiri ke kanan, atau dalam kasus di mana lebih efisien untuk memulai pencocokan di bagian kanan pola alih-alih kiri. Seperti yang digambarkan contoh berikut, menggunakan pencocokan kanan-ke-kiri dapat mengubah perilaku kuantifer serakah. Contoh ini melakukan dua pencarian untuk kalimat yang diakhiri dengan angka. Pencarian kiri-ke-kanan yang menggunakan kuantifier serakah + cocok dengan salah satu dari enam digit dalam kalimat, sedangkan pencarian kanan-ke-kiri cocok dengan keenam digit. Untuk deskripsi pola regex, lihat contoh yang menggambarkan kuantifer malas sebelumnya di bagian ini.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string greedyPattern = @".+(\d+)\.";
            string input = "This sentence ends with the number 107325.";
            Match match;
    
            // Match from left-to-right using lazy quantifier .+?.
            match = Regex.Match(input, greedyPattern);
            if (match.Success)
                Console.WriteLine("Number at end of sentence (left-to-right): {0}",
                                  match.Groups[1].Value);
            else
                Console.WriteLine("{0} finds no match.", greedyPattern);
    
            // Match from right-to-left using greedy quantifier .+.
            match = Regex.Match(input, greedyPattern, RegexOptions.RightToLeft);
            if (match.Success)
                Console.WriteLine("Number at end of sentence (right-to-left): {0}",
                                  match.Groups[1].Value);
            else
                Console.WriteLine("{0} finds no match.", greedyPattern);
        }
    }
    // The example displays the following output:
    //       Number at end of sentence (left-to-right): 5
    //       Number at end of sentence (right-to-left): 107325
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim greedyPattern As String = ".+(\d+)\."
            Dim input As String = "This sentence ends with the number 107325."
            Dim match As Match
    
            ' Match from left-to-right using lazy quantifier .+?.
            match = Regex.Match(input, greedyPattern)
            If match.Success Then
                Console.WriteLine("Number at end of sentence (left-to-right): {0}",
                                  match.Groups(1).Value)
            Else
                Console.WriteLine("{0} finds no match.", greedyPattern)
            End If
    
            ' Match from right-to-left using greedy quantifier .+.
            match = Regex.Match(input, greedyPattern, RegexOptions.RightToLeft)
            If match.Success Then
                Console.WriteLine("Number at end of sentence (right-to-left): {0}",
                                  match.Groups(1).Value)
            Else
                Console.WriteLine("{0} finds no match.", greedyPattern)
            End If
        End Sub
    End Module
    ' The example displays the following output:
    '       Number at end of sentence (left-to-right): 5
    '       Number at end of sentence (right-to-left): 107325
    

    Untuk informasi selengkapnya tentang pencocokan kanan-ke-kiri, lihat Opsi Regex.

  • Lookbehind positif dan negatif: (?<=subekspresi) untuk lookbehind positif, dan (?<!subekspresi) untuk lookbehind negatif. Fitur ini mirip dengan lookahead, yang dibahas sebelumnya dalam topik ini. Karena mesin regex memungkinkan pencocokan kanan-ke-kiri yang lengkap, regex memungkinkan lookbehind yang tidak dibatasi. Lookbehind positif dan negatif juga dapat digunakan untuk menghindari kuantifer berlapis saat subekspresi berlapis adalah superset dari ekspresi luar. Regex dengan kuantifer berlapis seperti itu sering menawarkan performa yang buruk. Misalnya, contoh berikut memverifikasi bahwa string dimulai dan diakhiri dengan karakter alfanumerik, dan bahwa karakter lain dalam string adalah salah satu subset yang lebih besar. Ini membentuk sebagian dari regex yang digunakan untuk memvalidasi alamat email; untuk informasi selengkapnya, lihat Cara: Memverifikasi bahwa String dalam Format Email yang Valid.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string[] inputs = { "jack.sprat", "dog#", "dog#1", "me.myself",
                              "me.myself!" };
            string pattern = @"^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$";
            foreach (string input in inputs)
            {
                if (Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase))
                    Console.WriteLine("{0}: Valid", input);
                else
                    Console.WriteLine("{0}: Invalid", input);
            }
        }
    }
    // The example displays the following output:
    //       jack.sprat: Valid
    //       dog#: Invalid
    //       dog#1: Valid
    //       me.myself: Valid
    //       me.myself!: Invalid
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim inputs() As String = {"jack.sprat", "dog#", "dog#1", "me.myself",
                                       "me.myself!"}
            Dim pattern As String = "^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$"
            For Each input As String In inputs
                If Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase) Then
                    Console.WriteLine("{0}: Valid", input)
                Else
                    Console.WriteLine("{0}: Invalid", input)
                End If
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '       jack.sprat: Valid
    '       dog#: Invalid
    '       dog#1: Valid
    '       me.myself: Valid
    '       me.myself!: Invalid
    

    Regex ^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$ didefinisikan seperti yang ditunjukkan pada tabel berikut.

    Pola Deskripsi
    ^ Mulailah pencocokan di awal string.
    [A-Z0-9] Cocokkan karakter numerik atau alfanumerik apa pun. (Perbandingannya tidak peka terhadap huruf besar/kecil.)
    ([-!#$%&'.*+/=?^`{}|~\w])* Cocokkan nol atau lebih kemunculan karakter kata apa pun, atau salah satu karakter berikut: -, !, #, $, %, &, ', ., *, +, /, =, ?, ^, ', {, }, |, atau ~.
    (?<=[A-Z0-9]) Lihatlah ke belakang pada karakter sebelumnya, yang harus berupa numerik atau alfanumerik. (Perbandingannya tidak peka terhadap huruf besar/kecil.)
    $ Akhiri pencocokan pada akhir string.

    Untuk informasi selengkapnya tentang lookbehind positif dan negatif, lihat Konstruksi Pengelompokan.

Judul Deskripsi
Pelacakan Balik Menyediakan informasi tentang bagaimana regex melakukan backtracking pada cabang untuk menemukan kecocokan alternatif.
Kompilasi dan Penggunaan Kembali Menyediakan informasi tentang mengompilasi dan menggunakan kembali regex untuk meningkatkan performa.
Thread Brankas ty Menyediakan informasi tentang keamanan utas regex dan menjelaskan kapan Anda harus menyinkronkan akses ke objek regex.
.NET Reges Memberikan gambaran umum tentang aspek bahasa pemrograman regex.
Model Objek Ekspresi Reguler Menyediakan informasi dan contoh kode yang menggambarkan cara menggunakan kelas regex.
Bahasa Regex - Referensi Cepat Menyediakan informasi tentang sekumpulan karakter, operator, dan konstruksi yang dapat Anda gunakan untuk mendefinisikan regex.

Referensi