unisbadri.com » Python Java Golang Typescript Kotlin Ruby Rust Dart PHP

Regex #

Package regexp di Go mengimplementasikan RE2 syntax — bukan PCRE (Perl Compatible Regular Expressions) yang dipakai Python, JavaScript, atau PHP. Perbedaan terpentingnya: RE2 tidak mendukung lookahead, lookbehind, dan backreference. Ini bukan keterbatasan sembarangan — RE2 menjamin waktu eksekusi linear terhadap panjang input, mencegah ReDoS (Regular Expression Denial of Service). Untuk sebagian besar kebutuhan validasi dan ekstraksi teks, RE2 lebih dari cukup. Artikel ini mencakup semua yang perlu kamu tahu untuk memakai regex secara efektif di Go.

Compile vs MustCompile #

Ada dua cara membuat objek *regexp.Regexp:

import "regexp"

// regexp.Compile — mengembalikan error jika pattern tidak valid
re, err := regexp.Compile(`\d{4}-\d{2}-\d{2}`)
if err != nil {
    log.Fatal("Pattern tidak valid:", err)
}

// regexp.MustCompile — panic jika pattern tidak valid
// Digunakan untuk pattern yang diketahui valid saat coding
re2 := regexp.MustCompile(`\d{4}-\d{2}-\d{2}`)

Kapan Menggunakan Masing-masing #

// GUNAKAN MustCompile untuk pattern literal di package-level
// Pattern dievaluasi sekali saat program mulai — panic = bug programmer, bukan user error
var (
    emailRegex = regexp.MustCompile(
        `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
    phoneRegex = regexp.MustCompile(`^(\+62|62|0)8[1-9][0-9]{6,9}$`)
    dateRegex  = regexp.MustCompile(`^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`)
    uuidRegex  = regexp.MustCompile(
        `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
)

// GUNAKAN Compile untuk pattern yang datang dari user input atau konfigurasi
func validateWithCustomPattern(input, pattern string) (bool, error) {
    re, err := regexp.Compile(pattern)
    if err != nil {
        return false, fmt.Errorf("pattern regex tidak valid: %w", err)
    }
    return re.MatchString(input), nil
}
Selalu compile regex sekali, pakai berkali-kali. Proses kompilasi regex (parsing, membangun finite automaton) cukup mahal. Jika kamu compile regex di dalam loop atau di dalam fungsi yang dipanggil berkali-kali, performa akan sangat buruk. Deklarasikan sebagai package-level var dengan MustCompile.

Raw String Literal — Cara Menulis Pattern yang Benar #

Regex sering mengandung banyak backslash. Di string biasa, backslash harus di-escape (\\), membuatnya sulit dibaca. Gunakan raw string literal (backtick) untuk regex:

// String biasa — backslash harus di-escape, susah dibaca
re1 := regexp.MustCompile("\\d{4}-\\d{2}-\\d{2}")
re1b := regexp.MustCompile("^[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}$")

// Raw string — lebih mudah dibaca
re2 := regexp.MustCompile(`\d{4}-\d{2}-\d{2}`)
re2b := regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)

Selalu gunakan backtick untuk regex — tidak ada pengecualian yang masuk akal.


Operasi Dasar #

MatchString — Apakah Ada Kecocokan? #

re := regexp.MustCompile(`\d+`)

fmt.Println(re.MatchString("abc123"))  // true — ada digit
fmt.Println(re.MatchString("abc"))     // false — tidak ada digit
fmt.Println(re.MatchString(""))        // false

// Match pada []byte
fmt.Println(re.Match([]byte("abc123")))  // true

FindString — Kecocokan Pertama #

re := regexp.MustCompile(`\d+`)

fmt.Println(re.FindString("abc123def456"))   // "123" — kecocokan pertama
fmt.Println(re.FindString("abcdef"))         // "" — tidak ada kecocokan

// FindString mengembalikan "" jika tidak ada kecocokan
// Gunakan FindStringIndex untuk membedakan "tidak ada" vs "string kosong cocok"

FindAllString — Semua Kecocokan #

Parameter kedua adalah limit: -1 untuk semua kecocokan, n untuk maksimum n kecocokan:

re := regexp.MustCompile(`\d+`)
text := "harga: 15000, diskon: 2000, total: 13000"

// Semua kecocokan
all := re.FindAllString(text, -1)
fmt.Println(all)  // [15000 2000 13000]

// Maksimum 2 kecocokan
two := re.FindAllString(text, 2)
fmt.Println(two)  // [15000 2000]

FindStringIndex — Posisi Kecocokan #

re := regexp.MustCompile(`\d+`)
text := "abc123def456"

idx := re.FindStringIndex(text)
fmt.Println(idx)  // [3 6] — kecocokan "123" di index 3 sampai 5 (tidak termasuk 6)

if idx != nil {
    fmt.Println(text[idx[0]:idx[1]])  // "123"
}

allIdx := re.FindAllStringIndex(text, -1)
fmt.Println(allIdx)  // [[3 6] [9 12]]

Capturing Groups #

Capturing groups dengan () memungkinkan mengekstrak bagian tertentu dari kecocokan:

// FindStringSubmatch — [full_match, group1, group2, ...]
re := regexp.MustCompile(`(\d{4})-(\d{2})-(\d{2})`)
text := "Tanggal lahir: 2024-07-28"

match := re.FindStringSubmatch(text)
fmt.Println(match)     // [2024-07-28 2024 07 28]
// match[0] = full match
// match[1] = tahun (group 1)
// match[2] = bulan (group 2)
// match[3] = hari (group 3)

if match != nil {
    fmt.Printf("Tahun: %s, Bulan: %s, Hari: %s\n",
        match[1], match[2], match[3])
}

// FindAllStringSubmatch — semua kecocokan dengan groups
re2 := regexp.MustCompile(`(\w+)=(\w+)`)
config := "host=localhost port=5432 db=myapp"

allMatches := re2.FindAllStringSubmatch(config, -1)
for _, m := range allMatches {
    fmt.Printf("key=%s, value=%s\n", m[1], m[2])
}
// key=host, value=localhost
// key=port, value=5432
// key=db, value=myapp

Named Groups — (?P<name>...) #

Named groups memungkinkan mengakses hasil berdasarkan nama, bukan index:

re := regexp.MustCompile(
    `(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})`)

text := "2024-07-28"
match := re.FindStringSubmatch(text)

// Dapatkan nama-nama group
names := re.SubexpNames()
fmt.Println(names)  // ["" "year" "month" "day"]

// Buat map dari nama ke nilai
result := make(map[string]string)
for i, name := range names {
    if i != 0 && name != "" && i < len(match) {
        result[name] = match[i]
    }
}

fmt.Println(result["year"])   // 2024
fmt.Println(result["month"])  // 07
fmt.Println(result["day"])    // 28

// Helper function yang lebih elegan
func namedGroups(re *regexp.Regexp, s string) map[string]string {
    match := re.FindStringSubmatch(s)
    if match == nil {
        return nil
    }
    result := make(map[string]string)
    for i, name := range re.SubexpNames() {
        if i != 0 && name != "" {
            result[name] = match[i]
        }
    }
    return result
}

Replace #

ReplaceAllString — Ganti dengan String Literal #

re := regexp.MustCompile(`\d+`)
text := "Harga: 15000, diskon: 2000"

// Ganti semua angka dengan "X"
fmt.Println(re.ReplaceAllString(text, "X"))
// "Harga: X, diskon: X"

// Gunakan $1, $2, ... untuk backreference ke captured group
re2 := regexp.MustCompile(`(\w+)@(\w+)\.(\w+)`)
email := "[email protected]"
masked := re2.ReplaceAllString(email, "$1@***.$3")
fmt.Println(masked)  // "budi@***.com"

ReplaceAllLiteralString — Ganti Tanpa Backreference #

re := regexp.MustCompile(`\$\d+`)
text := "Harga: $100 dan $200"

// Dengan ReplaceAllString, $ diinterpretasikan sebagai group reference
// Gunakan ReplaceAllLiteralString jika replacement mengandung $
fmt.Println(re.ReplaceAllLiteralString(text, "USD"))
// "Harga: USD dan USD"

ReplaceAllStringFunc — Ganti dengan Fungsi #

Ini adalah fitur paling powerful — kamu bisa mengubah setiap kecocokan secara programatik:

// Konversi semua kata menjadi title case
re := regexp.MustCompile(`\b\w+\b`)
text := "the quick brown fox"

result := re.ReplaceAllStringFunc(text, func(match string) string {
    if len(match) == 0 {
        return match
    }
    return strings.ToUpper(match[:1]) + match[1:]
})
fmt.Println(result)  // "The Quick Brown Fox"

// Masking email — tampilkan hanya 2 karakter pertama
emailRe := regexp.MustCompile(`\b[\w.]+@[\w.]+\b`)
logLine := "User [email protected] login dari IP 192.168.1.1"

masked := emailRe.ReplaceAllStringFunc(logLine, func(email string) string {
    parts := strings.Split(email, "@")
    if len(parts) != 2 {
        return email
    }
    user := parts[0]
    if len(user) > 2 {
        user = user[:2] + strings.Repeat("*", len(user)-2)
    }
    return user + "@" + parts[1]
})
fmt.Println(masked)  // "User bu**********@gmail.com login dari IP 192.168.1.1"

Split #

re := regexp.MustCompile(`[\s,;]+`)  // split pada spasi, koma, atau titik koma

text := "apel, mangga; jeruk  durian"
parts := re.Split(text, -1)
fmt.Println(parts)  // [apel mangga jeruk durian]

// SplitN — maksimum n bagian
parts2 := re.Split(text, 3)
fmt.Println(parts2)  // [apel mangga jeruk  durian] — hanya 2 split

Flags #

Flags mengubah perilaku pencocokan. Di RE2, flags ditulis di dalam pattern:

// (?i) — case insensitive
re := regexp.MustCompile(`(?i)golang`)
fmt.Println(re.MatchString("Golang"))   // true
fmt.Println(re.MatchString("GOLANG"))   // true
fmt.Println(re.MatchString("gOlAnG"))   // true

// (?m) — multiline: ^ dan $ cocok di awal/akhir setiap baris
re2 := regexp.MustCompile(`(?m)^\d+`)
text := "123 abc\n456 def\n789 ghi"
fmt.Println(re2.FindAllString(text, -1))  // [123 456 789]

// (?s) — dot-all: . juga cocok dengan newline
re3 := regexp.MustCompile(`(?s)start.+end`)
fmt.Println(re3.MatchString("start\nmiddle\nend"))  // true

// (?im) — kombinasi beberapa flag
re4 := regexp.MustCompile(`(?im)^hello`)

// Flags berlaku untuk keseluruhan pattern kecuali ditempatkan di grup
// (?i:kata) — flag hanya berlaku untuk grup ini
re5 := regexp.MustCompile(`(?i:go)lang`)
fmt.Println(re5.MatchString("Golang"))   // true — "Go" case-insensitive
fmt.Println(re5.MatchString("golANG"))   // false — "lang" masih case-sensitive

Sintaks RE2 Penting #

ANCHORS:
  ^        Awal string (atau baris dengan flag (?m))
  $        Akhir string (atau baris dengan flag (?m))
  \A       Awal string (tidak terpengaruh (?m))
  \z       Akhir string (tidak terpengaruh (?m))

CHARACTER CLASSES:
  .        Karakter apapun kecuali newline (dengan (?s) termasuk newline)
  \d       Digit [0-9]
  \D       Non-digit
  \w       Word character [0-9A-Za-z_]
  \W       Non-word character
  \s       Whitespace [ \t\n\f\r]
  \S       Non-whitespace
  [abc]    Character class: a, b, atau c
  [^abc]   Negated: bukan a, b, atau c
  [a-z]    Range: a sampai z
  [a-zA-Z0-9] Alphanumeric

QUANTIFIERS:
  *        0 atau lebih (greedy)
  +        1 atau lebih (greedy)
  ?        0 atau 1 (greedy)
  *?       0 atau lebih (lazy/non-greedy)
  +?       1 atau lebih (lazy/non-greedy)
  ??       0 atau 1 (lazy)
  {n}      Tepat n
  {n,}     n atau lebih
  {n,m}    Antara n dan m

GROUPS:
  (abc)    Capturing group
  (?:abc)  Non-capturing group
  (?P<name>abc) Named capturing group
  (a|b)    Alternation: a atau b

TIDAK ADA DI RE2 (berbeda dari PCRE):
  (?=...)  Lookahead — TIDAK DIDUKUNG
  (?!...)  Negative lookahead — TIDAK DIDUKUNG
  (?<=...) Lookbehind — TIDAK DIDUKUNG
  \1, \2   Backreference — TIDAK DIDUKUNG

Pola Regex Umum untuk Validasi #

var (
    // Email — sederhana tapi mencakup kebanyakan kasus
    EmailRegex = regexp.MustCompile(
        `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)

    // Nomor telepon Indonesia
    PhoneIDRegex = regexp.MustCompile(
        `^(\+62|62|0)(8[1-9])[0-9]{6,9}$`)

    // URL (sederhana)
    URLRegex = regexp.MustCompile(
        `^https?://[^\s/$.?#].[^\s]*$`)

    // Tanggal ISO 8601 (YYYY-MM-DD)
    DateRegex = regexp.MustCompile(
        `^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`)

    // IP Address v4
    IPv4Regex = regexp.MustCompile(
        `^(25[0-5]|2[0-4]\d|[01]?\d\d?)(\.(25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$`)

    // UUID v4
    UUIDRegex = regexp.MustCompile(
        `^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`)

    // Username: huruf, angka, underscore, 3-20 karakter
    UsernameRegex = regexp.MustCompile(`^[a-zA-Z0-9_]{3,20}$`)

    // Password: min 8 karakter, ada huruf besar, kecil, angka
    // (validasi kompleks lebih baik dengan logika Go daripada regex)

    // Kode pos Indonesia (5 digit)
    PostalCodeIDRegex = regexp.MustCompile(`^\d{5}$`)

    // NIK KTP (16 digit)
    NIKRegex = regexp.MustCompile(`^\d{16}$`)

    // Plat nomor kendaraan Indonesia (sederhana)
    LicensePlateRegex = regexp.MustCompile(
        `^[A-Z]{1,2}\s?\d{1,4}\s?[A-Z]{1,3}$`)
)

Kapan TIDAK Menggunakan Regex #

Regex bukan solusi untuk semua masalah string. Untuk operasi sederhana, strings package jauh lebih cepat dan lebih mudah dibaca:

// ANTI-PATTERN: regex untuk operasi string sederhana
hasPrefix := regexp.MustCompile(`^Hello`).MatchString(text)
hasSuffix := regexp.MustCompile(`World$`).MatchString(text)
contains  := regexp.MustCompile(`golang`).MatchString(text)

// BENAR: gunakan strings package
hasPrefix2 := strings.HasPrefix(text, "Hello")
hasSuffix2 := strings.HasSuffix(text, "World")
contains2  := strings.Contains(text, "golang")

// Untuk split sederhana
parts := regexp.MustCompile(`\s+`).Split(text, -1)
// Lebih baik:
parts2 := strings.Fields(text)  // split whitespace

// Untuk replace sederhana
result := regexp.MustCompile(`old`).ReplaceAllString(text, "new")
// Lebih baik:
result2 := strings.ReplaceAll(text, "old", "new")
Gunakan regex ketika:
  ✓ Pattern dinamis atau kompleks
  ✓ Perlu capturing groups untuk ekstraksi
  ✓ Validasi dengan aturan yang tidak bisa diekspresikan dengan strings
  ✓ Parsing teks yang tidak terstruktur

Gunakan strings package ketika:
  ✓ Cek prefix/suffix — strings.HasPrefix/HasSuffix
  ✓ Cek keberadaan substring — strings.Contains
  ✓ Split pada delimiter tetap — strings.Split
  ✓ Ganti string literal — strings.ReplaceAll
  ✓ Case conversion — strings.ToUpper/ToLower

Contoh Program Lengkap #

Program berikut membangun form validator yang menggunakan berbagai pola regex:

package main

import (
    "fmt"
    "regexp"
    "strings"
)

// ── Regex Patterns ────────────────────────────────────────────

var (
    reEmail = regexp.MustCompile(
        `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)

    rePhone = regexp.MustCompile(
        `^(\+62|62|0)(8[1-9])[0-9]{6,9}$`)

    reUsername = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_]{2,19}$`)

    reURL = regexp.MustCompile(
        `^https?://[a-zA-Z0-9\-._~:/?#\[\]@!$&'()*+,;=%]+$`)

    reDate = regexp.MustCompile(
        `^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`)

    reHTMLTag = regexp.MustCompile(`<[^>]+>`)

    reWhitespace = regexp.MustCompile(`\s+`)

    reNumber = regexp.MustCompile(`\b\d+(?:\.\d+)?\b`)

    reHashtag = regexp.MustCompile(`#(\w+)`)

    reMention = regexp.MustCompile(`@(\w+)`)
)

// ── Validation Result ─────────────────────────────────────────

type ValidationResult struct {
    Field   string
    Value   string
    Valid   bool
    Message string
}

func validate(field, value string, re *regexp.Regexp, msg string) ValidationResult {
    valid := re.MatchString(value)
    result := ValidationResult{Field: field, Value: value, Valid: valid}
    if !valid {
        result.Message = msg
    }
    return result
}

// ── Text Processing ───────────────────────────────────────────

// StripHTML menghapus semua HTML tag dari teks
func stripHTML(html string) string {
    return reHTMLTag.ReplaceAllString(html, "")
}

// NormalizeWhitespace mengganti whitespace berulang dengan satu spasi
func normalizeWhitespace(s string) string {
    return strings.TrimSpace(reWhitespace.ReplaceAllString(s, " "))
}

// ExtractNumbers mengekstrak semua angka dari teks
func extractNumbers(text string) []string {
    return reNumber.FindAllString(text, -1)
}

// ExtractHashtags mengekstrak semua hashtag dari teks
func extractHashtags(text string) []string {
    matches := reHashtag.FindAllStringSubmatch(text, -1)
    tags := make([]string, 0, len(matches))
    for _, m := range matches {
        tags = append(tags, m[1])  // ambil grup 1, bukan full match
    }
    return tags
}

// ExtractMentions mengekstrak semua mention dari teks
func extractMentions(text string) []string {
    matches := reMention.FindAllStringSubmatch(text, -1)
    mentions := make([]string, 0, len(matches))
    for _, m := range matches {
        mentions = append(mentions, m[1])
    }
    return mentions
}

// ParseDate mengekstrak komponen tanggal
func parseDate(s string) (year, month, day string, ok bool) {
    m := reDate.FindStringSubmatch(s)
    if m == nil {
        return "", "", "", false
    }
    return m[1], m[2], m[3], true
}

// MaskEmail menyamarkan bagian email
func maskEmail(email string) string {
    reMask := regexp.MustCompile(`^(.{2})(.+)(@.+)$`)
    return reMask.ReplaceAllStringFunc(email, func(s string) string {
        m := reMask.FindStringSubmatch(s)
        if m == nil {
            return s
        }
        hidden := strings.Repeat("*", len(m[2]))
        return m[1] + hidden + m[3]
    })
}

// ── Main ──────────────────────────────────────────────────────

func main() {
    fmt.Println("=== Form Validator ===\n")

    // Data form yang akan divalidasi
    testCases := []struct {
        field string
        value string
        re    *regexp.Regexp
        msg   string
    }{
        {"email", "[email protected]", reEmail, "Format email tidak valid"},
        {"email", "bukan-email", reEmail, "Format email tidak valid"},
        {"email", "user@domain", reEmail, "Format email tidak valid"},
        {"phone", "+6281234567890", rePhone, "Nomor telepon tidak valid"},
        {"phone", "08123456789", rePhone, "Nomor telepon tidak valid"},
        {"phone", "123456", rePhone, "Nomor telepon tidak valid"},
        {"username", "budi_santoso", reUsername, "Username: 3-20 karakter, huruf/angka/underscore"},
        {"username", "b", reUsername, "Username: 3-20 karakter, huruf/angka/underscore"},
        {"username", "1invalid", reUsername, "Username harus diawali huruf"},
        {"url", "https://www.google.com", reURL, "URL tidak valid"},
        {"url", "ftp://server.com", reURL, "URL harus dimulai http/https"},
        {"date", "2024-07-28", reDate, "Format tanggal: YYYY-MM-DD"},
        {"date", "2024-13-01", reDate, "Bulan tidak valid"},
        {"date", "28-07-2024", reDate, "Format tanggal: YYYY-MM-DD"},
    }

    for _, tc := range testCases {
        r := validate(tc.field, tc.value, tc.re, tc.msg)
        status := "✓"
        detail := ""
        if !r.Valid {
            status = "✗"
            detail = " → " + r.Message
        }
        fmt.Printf("  [%s] %-10s: %q%s\n", status, r.Field, r.Value, detail)
    }

    fmt.Println("\n=== Text Processing ===\n")

    // HTML stripping
    html := `<h1>Judul</h1><p>Ini adalah <strong>teks</strong> dengan <em>format</em>.</p>`
    fmt.Printf("HTML    : %s\n", html)
    fmt.Printf("Stripped: %s\n\n", stripHTML(html))

    // Whitespace normalization
    messy := "  Teks    dengan    banyak     spasi  "
    fmt.Printf("Messy    : %q\n", messy)
    fmt.Printf("Normalized: %q\n\n", normalizeWhitespace(messy))

    // Ekstraksi angka
    receipt := "Beli 3 apel @ Rp5000, total Rp15000 + pajak Rp1500 = Rp16500"
    numbers := extractNumbers(receipt)
    fmt.Printf("Teks   : %s\n", receipt)
    fmt.Printf("Angka  : %v\n\n", numbers)

    // Ekstraksi hashtag dan mention dari teks media sosial
    post := "Baru belajar #golang dan #programming! Terima kasih @gopher dan @godev atas tutorialnya!"
    hashtags := extractHashtags(post)
    mentions := extractMentions(post)
    fmt.Printf("Post     : %s\n", post)
    fmt.Printf("Hashtags : %v\n", hashtags)
    fmt.Printf("Mentions : %v\n\n", mentions)

    // Parse tanggal
    dateStr := "2024-07-28"
    if year, month, day, ok := parseDate(dateStr); ok {
        fmt.Printf("Parse %q: tahun=%s, bulan=%s, hari=%s\n",
            dateStr, year, month, day)
    }

    // Email masking
    emails := []string{
        "[email protected]",
        "[email protected]",
        "[email protected]",
    }
    fmt.Println("\nEmail masking:")
    for _, e := range emails {
        fmt.Printf("  %-35s → %s\n", e, maskEmail(e))
    }

    // Demonstrasi ReplaceAllStringFunc — format angka dengan pemisah ribuan
    fmt.Println("\nFormat angka:")
    reRupiahValue := regexp.MustCompile(`\d+`)
    prices := "harga: 15000000, diskon: 500000, total: 14500000"
    formatted := reRupiahValue.ReplaceAllStringFunc(prices, func(s string) string {
        n := len(s)
        if n <= 3 {
            return s
        }
        var result strings.Builder
        for i, c := range s {
            if i > 0 && (n-i)%3 == 0 {
                result.WriteByte('.')
            }
            result.WriteRune(c)
        }
        return result.String()
    })
    fmt.Printf("  %s\n", formatted)
}

Ringkasan #

  • Go menggunakan RE2, bukan PCRE — tidak ada lookahead, lookbehind, atau backreference; tapi dijamin linear time (aman dari ReDoS).
  • MustCompile untuk pattern literal di package-level — panic saat startup lebih baik dari panic saat runtime karena bug programmer.
  • Compile untuk pattern dari input eksternal — selalu tangani error-nya.
  • Selalu pakai raw string literal (backtick) untuk regex — menghindari double-escaping backslash.
  • Compile sekali, pakai berkali-kali — deklarasikan sebagai package-level var, bukan di dalam fungsi yang dipanggil berulang.
  • FindAllString(text, -1)-1 berarti semua kecocokan; gunakan n untuk membatasi jumlah.
  • FindStringSubmatch mengembalikan [full_match, group1, group2, ...]; index 0 selalu full match.
  • Named groups (?P<name>...) dan SubexpNames() untuk akses berdasarkan nama, bukan index.
  • ReplaceAllStringFunc untuk transformasi programatik setiap kecocokan — sangat fleksibel.
  • Jangan gunakan regex untuk operasi string sederhanastrings.Contains, HasPrefix, Split, ReplaceAll jauh lebih cepat dan lebih mudah dibaca.

← Sebelumnya: Date & Time   Berikutnya: Vendoring →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact