Tips dan pemecahan masalah saat menulis parser

Dokumen ini menjelaskan masalah yang mungkin Anda temui saat menulis kode parser.

Saat menulis kode parser, Anda mungkin mengalami error saat petunjuk penguraian tidak berfungsi seperti yang diharapkan. Situasi yang mungkin menghasilkan error meliputi:

  • Pola Grok gagal
  • Operasi rename atau replace gagal
  • Error sintaksis dalam kode parser

Praktik umum dalam kode parser

Bagian berikut menjelaskan praktik terbaik, tips, dan solusi untuk membantu memecahkan masalah.

Hindari penggunaan titik atau tanda hubung dalam nama variabel

Penggunaan tanda hubung dan titik pada nama variabel dapat menyebabkan perilaku yang tidak terduga, sering kali saat melakukan operasi merge untuk menyimpan nilai dalam kolom UDM. Anda mungkin juga mengalami masalah penguraian yang terputus-putus.

Misalnya, jangan gunakan nama variabel berikut:

  • my.variable.result
  • my-variable-result

Sebagai gantinya, gunakan nama variabel berikut: my_variable_result.

Jangan gunakan istilah dengan arti khusus sebagai nama variabel

Kata tertentu, seperti event dan timestamp, dapat memiliki arti khusus dalam kode parser.

String event sering digunakan untuk mewakili satu data UDM dan digunakan dalam pernyataan @output. Jika pesan log menyertakan kolom yang disebut event, atau jika Anda menentukan variabel perantara yang disebut event, dan kode parser menggunakan kata event dalam pernyataan @output, Anda akan mendapatkan pesan error tentang konflik nama.

Ganti nama variabel perantara menjadi yang lain, atau gunakan istilah event1 sebagai awalan dalam nama kolom UDM dan dalam pernyataan @output.

Kata timestamp mewakili stempel waktu yang dibuat dari log mentah asli. Nilai yang ditetapkan dalam variabel perantara ini disimpan ke kolom UDM metadata.event_timestamp. Istilah @timestamp menunjukkan tanggal dan waktu saat log mentah diurai untuk membuat data UDM.

Contoh berikut menetapkan kolom UDM metadata.event_timestamp ke tanggal dan waktu saat log mentah diuraikan.

 # Save the log parse date and time to the timestamp variable
  mutate {
     rename => {
       "@timestamp" => "timestamp"
     }
   }

Contoh berikut menetapkan kolom UDM metadata.event_timestamp ke tanggal dan waktu yang diekstrak dari log mentah asli dan disimpan dalam variabel perantara when.

   # Save the event timestamp to timestamp variable
   mutate {
     rename => {
       "when" => "timestamp"
     }
   }

Jangan gunakan istilah berikut sebagai variabel:

  • stempel waktu koleksi
  • buatstempel waktu
  • event
  • filename
  • pesan
  • namespace
  • output
  • onerrorcount
  • timestamp
  • zona waktu

Simpan setiap nilai data dalam kolom UDM terpisah

Jangan menyimpan beberapa kolom dalam satu kolom UDM dengan menggabungkannya menggunakan pembatas. Berikut adalah contohnya:

"principal.user.first_name" => "first:%{first_name},last:%{last_name}"

Simpan setiap nilai di kolom UDM terpisah.

"principal.user.first_name" => "%{first_name}"
"principal.user.last_name" => "%{last_name}"

Menggunakan spasi, bukan tab dalam kode

Jangan gunakan tab dalam kode parser. Hanya gunakan spasi dan indentasi 2 spasi sekaligus.

Jangan melakukan beberapa tindakan penggabungan dalam satu operasi

Jika Anda menggabungkan beberapa kolom dalam satu operasi, hal ini dapat menyebabkan hasil yang tidak konsisten. Sebagai gantinya, tempatkan pernyataan merge ke dalam operasi terpisah.

Misalnya, ganti contoh berikut:

mutate {
  merge => {
      "security_result.category_details" => "category_details"
      "security_result.category_details" => "super_category_details"
  }
}

Dengan ini:

mutate {
  merge => {
    "security_result.category_details" => "category_details"
  }
}

mutate {
  merge => {
    "security_result.category_details" => "super_category_details"
  }
}

Memilih ekspresi bersyarat if versus if else

Jika nilai kondisional yang sedang Anda uji hanya dapat memiliki satu kecocokan, gunakan pernyataan kondisional if else. Pendekatan ini sedikit lebih efisien. Namun, jika Anda memiliki skenario dengan nilai yang diuji dapat cocok lebih dari satu kali, gunakan beberapa pernyataan if yang berbeda dan urutkan pernyataan tersebut dari kasus yang paling umum ke kasus yang paling spesifik.

Pilih kumpulan file log yang representatif untuk menguji perubahan parser

Praktik terbaiknya adalah menguji kode parser menggunakan sampel log mentah dengan berbagai format yang luas. Hal ini memungkinkan Anda menemukan log atau kasus ekstrem unik yang mungkin perlu ditangani oleh parser.

Menambahkan komentar deskriptif ke kode parser

Tambahkan komentar ke kode parser yang menjelaskan alasan pentingnya pernyataan, bukan fungsi pernyataan tersebut. Komentar ini membantu siapa pun yang mengelola parser untuk mengikuti alur. Berikut adalah contohnya:

# only assign a Namespace if the source address is RFC 1918 or Loopback IP address
if [jsonPayload][id][orig_h] =~ /^(127(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{3\}$)|(10(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{3\}$)|(192\.168(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{2\}$)|(172\.(?:1[6-9]|2\d|3[0-1])(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{2\}$)/ {
  mutate {
    replace => {
      "event1.idm.read_only_udm.principal.namespace" => "%{resource.labels.project_id}"
    }
  }
}

Menginisialisasi variabel perantara lebih awal

Sebelum mengekstrak nilai dari log mentah asli, inisialisasi variabel menengah yang akan digunakan untuk menyimpan nilai pengujian.

Hal ini mencegah error ditampilkan yang menunjukkan bahwa variabel perantara tidak ada.

Pernyataan berikut menetapkan nilai dalam variabel product ke kolom UDM metadata.product_name.

mutate{
  replace => {
    "event1.idm.read_only_udm.metadata.product_name" => "%{product}"
  }
}

Jika variabel product tidak ada, Anda akan mendapatkan error berikut:

"generic::invalid_argument: pipeline failed: filter mutate (4) failed: replace failure: field \"event1.idm.read_only_udm.metadata.product_name\": source field \"product\": field not set"

Anda dapat menambahkan pernyataan on_error untuk mendeteksi error. Berikut adalah contohnya:

mutate{
  replace => {
    "event1.idm.read_only_udm.metadata.product_name" => "%{product}"
    }
  on_error => "_error_does_not_exist"
  }

Contoh pernyataan sebelumnya berhasil menangkap error penguraian menjadi variabel perantara boolean, yang disebut _error_does_not_exist. Ini tidak memungkinkan Anda menggunakan variabel product dalam pernyataan kondisional, misalnya if. Berikut adalah contohnya:

if [product] != "" {
  mutate{
    replace => {
      "event1.idm.read_only_udm.metadata.product_name" => "%{product}"
    }
  }
  on_error => "_error_does_not_exist"
}

Contoh sebelumnya menampilkan error berikut karena klausa bersyarat if tidak mendukung pernyataan on_error:

"generic::invalid_argument: pipeline failed: filter conditional (4) failed: failed to evaluate expression: generic::invalid_argument: "product" not found in state data"

Untuk mengatasi hal ini, tambahkan blok pernyataan terpisah yang menginisialisasi variabel perantara sebelum mengeksekusi pernyataan filter ekstraksi (json, csv, xml, kv, atau grok). Berikut adalah contohnya.

filter {
  # Initialize intermediate variables for any field you will use for a conditional check
  mutate {
    replace => {
      "timestamp" => ""
      "does_not_exist" => ""
    }
  }

  # load the logs fields from the message field
  json {
    source         => "message"
    array_function => "split_columns"
    on_error       => "_not_json"
  }
}

Cuplikan kode parser yang diperbarui menangani beberapa skenario menggunakan pernyataan bersyarat untuk memeriksa apakah kolom ada. Selain itu, pernyataan on_error menangani error yang mungkin terjadi.

Mengonversi SHA-256 menjadi base64

Contoh berikut mengekstrak nilai SHA-256, mengenkodenya dalam base64, mengonversi data yang dienkode menjadi string heksadesimal, lalu mengganti kolom tertentu dengan nilai yang diekstrak dan diproses.

if [Sha256] != ""
{
  base64
  {
  encoding => "RawStandard"
  source => "Sha256"
  target => "base64_sha256"
  on_error => "base64_message_error"
  }
  mutate
  {
    convert =>
    {
      "base64_sha256" => "bytestohex"
    }
    on_error => "already_a_string"
  }
  mutate
  {
    replace =>
  {
     "event.idm.read_only_udm.network.tls.client.certificate.sha256" => "%{base64_sha256}"
     "event.idm.read_only_udm.target.resource.name" => "%{Sha256}"
  }
  }
}

Menangani error dalam pernyataan parser

Tidak jarang log masuk memiliki format log yang tidak terduga atau memiliki data yang diformat dengan buruk.

Anda dapat membuat parser untuk menangani error ini. Praktik terbaiknya adalah menambahkan pengendali on_error ke filter ekstraksi, lalu menguji variabel perantara sebelum melanjutkan ke segmen logika parser berikutnya.

Contoh berikut menggunakan filter ekstraksi json dengan pernyataan on_error untuk menetapkan variabel boolean _not_json. Jika _not_json disetel ke true, artinya entri log yang masuk tidak dalam format JSON yang valid dan entri log tidak berhasil diuraikan. Jika variabel _not_json adalah false, berarti entri log yang masuk memiliki format JSON yang valid.

 # load the incoming log from the default message field
  json {
    source         => "message"
    array_function => "split_columns"
    on_error       => "_not_json"
  }

Anda juga dapat menguji apakah format kolom sudah benar. Contoh berikut memeriksa apakah _not_json disetel ke true, yang menunjukkan bahwa log tidak dalam format yang diharapkan.

 # Test that the received log matches the expected format
  if [_not_json] {
    drop { tag => "TAG_MALFORMED_MESSAGE" }
  } else {
    # timestamp is always expected
    if [timestamp] != "" {

      # ...additional parser logic goes here …

    } else {

      # if the timestamp field does not exist, it's not a log source
      drop { tag => "TAG_UNSUPPORTED" }
    }
  }

Hal ini memastikan bahwa penguraian tidak akan gagal jika log diserap dengan format yang salah untuk jenis log yang ditentukan.

Gunakan filter drop dengan variabel tag sehingga kondisinya tercakup dalam tabel metrik penyerapan di BigQuery.

  • TAG_UNSUPPORTED
  • TAG_MALFORMED_ENCODING
  • TAG_MALFORMED_MESSAGE
  • TAG_NO_SECURITY_VALUE

Filter drop menghentikan parser agar tidak memproses log mentah, menormalisasi kolom, dan membuat data UDM. Log mentah asli masih diserap ke Chronicle dan dapat ditelusuri menggunakan penelusuran log mentah di Chronicle.

Nilai yang diteruskan ke variabel tag disimpan di kolom drop_reason_code dalam tabel metrik Penyerapan. Anda dapat menjalankan kueri ad hoc terhadap tabel seperti berikut:

SELECT
  log_type,
  drop_reason_code,
  COUNT(drop_reason_code) AS count
FROM `datalake.ingestion_metrics`
GROUP BY 1,2
ORDER BY 1 ASC

Memecahkan masalah error validasi

Saat mem-build parser, Anda mungkin mengalami error terkait validasi, misalnya kolom wajib diisi belum ditetapkan dalam data UDM. Error tersebut mungkin terlihat seperti berikut:

Error: generic::unknown: invalid event 0: LOG_PARSING_GENERATED_INVALID_EVENT: "generic::invalid_argument: udm validation failed: target field is not set"

Kode parser berhasil dieksekusi, tetapi data UDM yang dihasilkan tidak menyertakan semua kolom UDM wajib seperti yang ditentukan oleh nilai yang ditetapkan ke metadata.event_type. Berikut adalah contoh tambahan yang dapat menyebabkan error ini:

  • Jika metadata.event_type adalah USER_LOGIN dan kolom UDM target.user value tidak ditetapkan.
  • Jika metadata.event_type adalah NETWORK_CONNECTION dan kolom UDM target.hostname tidak ditetapkan.

Untuk mengetahui informasi selengkapnya tentang kolom UDM metadata.event_type dan kolom wajib, lihat panduan penggunaan UDM.

Salah satu opsi untuk memecahkan masalah jenis error ini adalah memulai dengan menetapkan nilai statis ke kolom UDM. Setelah Anda menentukan semua kolom UDM yang diperlukan, periksa log mentah asli untuk melihat nilai mana yang akan diurai dan disimpan ke data UDM. Jika log mentah asli tidak berisi kolom tertentu, Anda mungkin perlu menetapkan nilai default.

Berikut adalah contoh template, khusus untuk jenis peristiwa USER_LOGIN, yang menggambarkan pendekatan ini.

Perhatikan berikut ini:

  • Template melakukan inisialisasi variabel perantara dan menetapkan masing-masing variabel ke string statis.
  • Kode di bagian Penetapan Kolom menetapkan nilai dalam variabel perantara ke kolom UDM.

Anda dapat meluaskan kode ini dengan menambahkan kolom UDM dan variabel perantara tambahan. Setelah Anda mengidentifikasi semua kolom UDM yang harus diisi, lakukan hal berikut:

  • Di bagian Konfigurasi Input, tambahkan kode yang mengekstrak kolom dari log mentah asli dan menetapkan nilainya ke variabel perantara.

  • Di bagian Ekstrak Tanggal, tambahkan kode yang mengekstrak stempel waktu peristiwa dari log mentah asli, mengubahnya, dan menetapkannya ke variabel perantara.

  • Bila perlu, ganti set nilai yang diinisialisasi di setiap variabel perantara menjadi string kosong.

filter {
 mutate {
   replace => {
     # UDM > Metadata
     "metadata_event_timestamp"    => ""
     "metadata_vendor_name"        => "Example"
     "metadata_product_name"       => "Example SSO"
     "metadata_product_version"    => "1.0"
     "metadata_product_event_type" => "login"
     "metadata_product_log_id"     => "12345678"
     "metadata_description"        => "A user logged in."
     "metadata_event_type"         => "USER_LOGIN"

     # UDM > Principal
     "principal_ip"       => "192.168.2.10"

     # UDM > Target
     "target_application"            => "Example Connect"
     "target_user_user_display_name" => "Mary Smith"
     "target_user_userid"            => "mary@example.com"

     # UDM > Extensions
     "auth_type"          => "SSO"
     "auth_mechanism"     => "USERNAME_PASSWORD"

     # UDM > Security Results
     "securityResult_action"         => "ALLOW"
     "security_result.severity"       => "LOW"

   }
 }

 # ------------ Input Configuration  --------------
  # Extract values from the message using one of the extraction filters: json, kv, grok

 # ------------ Date Extract  --------------
 # If the  date {} function is not used, the default is the normalization process time

  # ------------ Field Assignment  --------------
  # UDM Metadata
  mutate {
    replace => {
      "event1.idm.read_only_udm.metadata.vendor_name"        =>  "%{metadata_vendor_name}"
      "event1.idm.read_only_udm.metadata.product_name"       =>  "%{metadata_product_name}"
      "event1.idm.read_only_udm.metadata.product_version"    =>  "%{metadata_product_version}"
      "event1.idm.read_only_udm.metadata.product_event_type" =>  "%{metadata_product_event_type}"
      "event1.idm.read_only_udm.metadata.product_log_id"     =>  "%{metadata_product_log_id}"
      "event1.idm.read_only_udm.metadata.description"        =>  "%{metadata_description}"
      "event1.idm.read_only_udm.metadata.event_type"         =>  "%{metadata_event_type}"
    }
  }

  # Set the UDM > auth fields
  mutate {
    replace => {
      "event1.idm.read_only_udm.extensions.auth.type"        => "%{auth_type}"
    }
    merge => {
      "event1.idm.read_only_udm.extensions.auth.mechanism"   => "auth_mechanism"
    }
  }

  # Set the UDM > principal fields
  mutate {
    merge => {
      "event1.idm.read_only_udm.principal.ip"                => "principal_ip"
    }
  }

  # Set the UDM > target fields
  mutate {
    replace => {
      "event1.idm.read_only_udm.target.user.userid"             =>  "%{target_user_userid}"
      "event1.idm.read_only_udm.target.user.user_display_name"  =>  "%{target_user_user_display_name}"
      "event1.idm.read_only_udm.target.application"             =>  "%{target_application}"
    }
  }

  # Set the UDM > security_results fields
  mutate {
    merge => {
      "security_result.action" => "securityResult_action"
    }
  }

  # Set the security result
  mutate {
    merge => {
      "event1.idm.read_only_udm.security_result" => "security_result"
    }
  }

 # ------------ Output the event  --------------
  mutate {
    merge => {
      "@output" => "event1"
    }
  }

}

Mengurai teks tidak terstruktur menggunakan fungsi Grok

Ketika menggunakan fungsi Grok untuk mengekstrak nilai dari teks tidak terstruktur, Anda dapat menggunakan pernyataan ekspresi reguler dan pola Grok yang telah ditentukan. Pola grok membuat kode lebih mudah dibaca. Jika ekspresi reguler tidak menyertakan karakter singkat (seperti \w, \s), Anda dapat menyalin dan menempelkan pernyataan tersebut langsung ke dalam kode parser.

Karena pola Grok adalah lapisan abstraksi tambahan dalam pernyataan, pola tersebut dapat membuat pemecahan masalah menjadi lebih kompleks saat Anda mengalami error. Berikut adalah contoh fungsi Grok yang berisi pola dan ekspresi reguler Grok yang telah ditetapkan.

grok {
  match => {
    "message" => [
      "%{NUMBER:when}\\s+\\d+\\s%{SYSLOGHOST:srcip} %{WORD:action}\\/%{NUMBER:returnCode} %{NUMBER:size} %{WORD:method} (?P<url>\\S+) (?P<username>.*?) %{WORD}\\/(?P<tgtip>\\S+).*"
    ]
  }
}

Pernyataan ekstraksi tanpa pola Grok mungkin berperforma lebih baik. Misalnya, contoh berikut membutuhkan waktu kurang dari setengah langkah pemrosesan untuk mencocokkan. Untuk sumber log dengan volume yang berpotensi tinggi, ini adalah pertimbangan penting.

Memahami perbedaan antara ekspresi reguler RE2 dan PCRE

Parser Chronicle menggunakan RE2 sebagai mesin ekspresi reguler. Jika sudah terbiasa dengan sintaksis PCRE, Anda mungkin melihat perbedaannya. Berikut adalah salah satu contohnya:

Berikut adalah pernyataan PCRE: (?<_custom_field>\w+)\s

Berikut adalah pernyataan RE2 untuk kode parser: (?P<_custom_field>\\w+)\\s

Pastikan untuk meng-escape karakter escape

Chronicle menyimpan data log mentah yang masuk dalam format yang dienkode JSON. Hal ini untuk memastikan bahwa string karakter yang tampak seperti versi singkat ekspresi reguler diinterpretasikan sebagai string literal. Misalnya, \t ditafsirkan sebagai string literal, bukan karakter tab.

Contoh berikut adalah log mentah asli dan log format yang dienkode JSON. Perhatikan karakter escape yang ditambahkan di depan setiap karakter garis miring terbalik yang mengelilingi istilah entry.

Berikut ini adalah log mentah asli:

field=\entry\

Berikut adalah log yang dikonversi ke format yang dienkode JSON:

field=\\entry\\

Saat menggunakan ekspresi reguler dalam kode parser, Anda harus menambahkan karakter escape tambahan jika ingin mengekstrak nilai saja. Untuk mencocokkan garis miring terbalik di log mentah asli, gunakan empat garis miring terbalik dalam pernyataan ekstraksi.

Berikut ini adalah ekspresi reguler untuk kode parser:

^field=\\\\(?P<_value>.*)\\\\$

Berikut adalah hasil yang dihasilkan. Grup bernama _value menyimpan istilah entry:

"_value": "entry"

Saat memindahkan pernyataan ekspresi reguler standar ke dalam kode parser, escape karakter singkat ekspresi reguler dalam pernyataan ekstraksi. Misalnya, ubah \s menjadi \\s.

Jangan ubah karakter khusus ekspresi reguler saat karakter khusus di-escape dua kali dalam pernyataan ekstraksi. Misalnya, \\ tetap tidak berubah sebagai \\.

Berikut adalah ekspresi reguler standar:

^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$

Ekspresi reguler berikut dimodifikasi agar berfungsi di dalam kode parser.

^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$

Tabel berikut merangkum kapan ekspresi reguler standar harus menyertakan karakter escape tambahan sebelum menyertakannya dalam kode parser.

Regular expression Ekspresi reguler dimodifikasi untuk kode parser Deskripsi perubahan

\s

\\s
Karakter singkat harus di-escape.

\.

\\.
Karakter yang sudah digunakan harus di-escape.

\\"

\\\"
Karakter yang sudah digunakan harus di-escape.

\]

\\]
Karakter yang sudah digunakan harus di-escape.

\|

\\|
Karakter yang sudah digunakan harus di-escape.

[^\\]+

[^\\\\]+
Karakter khusus dalam grup class karakter harus di-escape.

\\\\

\\\\
Karakter khusus di luar kelompok class karakter atau karakter singkat tidak memerlukan escape tambahan.

Ekspresi reguler harus menyertakan grup tangkapan bernama

Ekspresi reguler, seperti "^.*$", adalah sintaksis RE2 yang valid. Namun, dalam kode parser, kode ini gagal dengan error berikut:

"ParseLogEntry failed: pipeline failed: filter grok (0) failed: failed to parse data with all match
patterns"

Anda harus menambahkan grup tangkapan yang valid ke ekspresi. Jika Anda menggunakan pola Grok, pola ini akan menyertakan grup tangkapan bernama secara default. Saat menggunakan penggantian ekspresi reguler, pastikan untuk menyertakan grup bernama.

Berikut adalah contoh ekspresi reguler dalam kode parser:

"^(?P<_catchall>.*$)"

Berikut adalah hasilnya, menampilkan teks yang ditetapkan ke grup bernama _catchall.

"_catchall": "User \"BOB\" logged on to workstation \"DESKTOP-01\"."

Gunakan grup bernama generik untuk memulai saat Anda membuat ekspresi

Saat membuat pernyataan ekstraksi, mulailah dengan ekspresi yang menangkap lebih dari yang Anda inginkan. Kemudian, luaskan kolom ekspresi satu per satu.

Contoh berikut dimulai dengan menggunakan grup bernama (_catchall) yang cocok dengan seluruh pesan. Kemudian, kode ini mem-build ekspresi secara bertahap dengan mencocokkan bagian teks lainnya. Untuk setiap langkah, grup bernama _catchall berisi lebih sedikit teks asli. Lanjutkan dan iterasi langkah demi langkah untuk mencocokkan pesan sampai Anda tidak lagi memerlukan grup bernama _catchall.

Langkah Ekspresi reguler dalam kode parser Output grup tangkapan bernama _catchall
1

"^(?P<_catchall>.*$)"

User \"BOB\" logged on to workstation \"DESKTOP-01\".
2

^User\s\\\"(?P<_catchall>.*$)

BOB\" logged on to workstation \"DESKTOP-01\".
3

^User\s\\\"(?P<_user>.*?)\\\"\s(?P<_catchall>.*$)

logged on to workstation \"DESKTOP-01\".
Lanjutkan hingga ekspresi cocok dengan seluruh string teks.

Meloloskan karakter singkatan dalam ekspresi reguler

Jangan lupa untuk meng-escape karakter singkatan ekspresi reguler saat menggunakan ekspresi dalam kode parser. Berikut adalah contoh string teks dan ekspresi reguler standar yang mengekstrak kata pertama, This.

  This is a sample log.

Ekspresi reguler standar berikut mengekstrak kata pertama, This. Namun, saat Anda menjalankan ekspresi ini dalam kode parser, hasilnya tidak akan memiliki huruf s.

Ekspresi reguler standar Output grup tangkapan bernama _firstWord
"^(?P<_firstWord>[^\s]+)\s.*$" "_firstWord": "Thi",

Hal ini karena ekspresi reguler dalam kode parser memerlukan karakter escape tambahan yang ditambahkan ke karakter pintasan. Pada contoh sebelumnya, \s harus diubah menjadi \\s.

Ekspresi reguler yang direvisi untuk kode parser Output grup tangkapan bernama _firstWord
"^(?P<_firstWord>[^\\s]+)\\s.*$" "_firstWord": "This",

Ini hanya berlaku untuk karakter singkatan, seperti \s, \r, dan \t. Karakter lain, seperti ``, tidak perlu di-escape lebih lanjut.

Contoh lengkap

Bagian ini menjelaskan aturan sebelumnya sebagai contoh menyeluruh. Berikut adalah string teks tidak terstruktur dan ekspresi reguler standar yang ditulis untuk mengurai string. Terakhir, contoh ini menyertakan ekspresi reguler yang dimodifikasi yang berfungsi dalam kode parser.

Berikut ini adalah string teks asli.

User "BOB" logged on to workstation "DESKTOP-01".

Berikut ini adalah ekspresi reguler RE2 standar yang mengurai string teks.

^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$

Ekspresi ini mengekstrak kolom berikut.

Grup pencocokan Posisi karakter String teks
Kecocokan penuh 0-53

User \"BOB\" logged on to workstation \"DESKTOP-01\".
Kelompokkan `_user` 7-10

BOB
Grup 2. 13-22

logged on
Kelompokkan `_device` 40-50

DESKTOP-01

Ini adalah ekspresi yang dimodifikasi. Ekspresi reguler RE2 standar dimodifikasi agar berfungsi dalam kode parser.

^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$