Regex tepat n ATAU m kali

105

Pertimbangkan ekspresi reguler berikut, di mana Xadalah setiap regex.

X{n}|X{m}

Regex ini akan menguji Xkemunculan tepat n atau mwaktu.

Apakah ada pembilang ekspresi reguler yang dapat menguji kejadian secara Xtepat natau mwaktu?

FThompson
sumber
Tidak. Dua kejadian Xadalah yang terbaik yang bisa Anda dapatkan untuk umum m, n.
John Dvorak
Jika ini adalah masalah saya, saya akan mencoba referensi latar regex dan akan memulainya (X)\1{n-1}(?:\1{m-n-1}). Saya tahu ini cocok Xsetidaknya sekali tetapi hanya untuk memulai, coba hal sederhana ini lalu perbaiki dengan menggunakan lookahead atau lookbehinds sebagai gantinya (X).
Nalply

Jawaban:

91

Tidak ada pembilang tunggal yang berarti "tepat m atau n kali". Cara Anda melakukannya baik-baik saja.

Alternatifnya adalah:

X{m}(X{k})?

di mana m < ndan kmerupakan nilai n-m.

Mark Byers
sumber
67

Berikut adalah daftar lengkap pembilang (ref. Http://www.regular-expressions.info/reference.html ):

  • ?, ??- 0 atau 1 kejadian ( ??malas, ?serakah)
  • *, *?- sejumlah kemunculan
  • +, +?- setidaknya satu kejadian
  • {n}- persis nkejadian
  • {n,m}- nuntuk mkejadian, inklusif
  • {n,m}?- nuntuk mkejadian, malas
  • {n,}, {n,}?- setidaknya nkejadian

Untuk mendapatkan "persis N atau M", Anda perlu menulis regex terkuantifikasi dua kali, kecuali m, n adalah spesial:

  • X{n,m} jika m = n+1
  • (?:X{n}){1,2} jika m = 2n
  • ...
John Dvorak
sumber
1
Mengapa ?:dibutuhkan dalam m = 2ncontoh if ? Sepertinya bekerja dengan baik tanpa itu untuk saya.
erb
7
@erb jika Anda keluar ?:, grup tersebut menjadi grup penangkap. Selain mesin regex yang mengingat hal-hal yang tidak perlu, jika Anda telah menangkap grup setelah ini, ID mereka akan berubah. Jika Anda menggunakan regex untuk substitusi, Anda harus menyesuaikan penggantinya.
John Dvorak
19

Tidak, tidak ada pembilang seperti itu. Tapi saya akan merestrukturnya /X{m}(X{m-n})?/untuk mencegah masalah mundur .

Bergi
sumber
3

TLDR; (?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

Sepertinya Anda menginginkan "xn times" atau "xm times", saya rasa terjemahan literal ke regex akan seperti (x{n}|x{m}). ini https://regex101.com/r/vH7yL5/1

atau, dalam kasus di mana Anda dapat memiliki urutan lebih dari m "x" s (dengan asumsi m> n), Anda dapat menambahkan 'setelah tidak ada "x"' dan 'diikuti dengan tidak ada "x", menerjemahkan ke [^x](x{n}|x{m})[^x]tapi itu akan asumsikan bahwa selalu ada karakter di belakang dan setelah Anda "x". Seperti yang Anda lihat di sini: https://regex101.com/r/bB2vH2/1

Anda dapat mengubahnya menjadi (?:[^x]|^)(x{n}|x{m})(?:[^x]|$), menerjemahkan menjadi "mengikuti no 'x' atau mengikuti baris awal" dan "diikuti dengan no 'x' atau diikuti oleh akhir baris". Tapi tetap saja, itu tidak akan cocok dengan dua urutan dengan hanya satu karakter di antara mereka (karena pertandingan pertama akan membutuhkan karakter setelahnya, dan yang kedua membutuhkan karakter sebelumnya) seperti yang Anda lihat di sini: https://regex101.com/r/ oC5oJ4 / 1

Terakhir, untuk mencocokkan satu karakter jauh yang cocok, Anda dapat menambahkan tampilan positif ke depan (? =) Pada "no 'x' setelah" atau tampilan positif di belakang (? <=) Pada "no 'x' before", seperti ini: https://regex101.com/r/mC4uX3/1

(?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

Dengan cara ini Anda hanya akan mencocokkan jumlah persis dari 'x yang Anda inginkan.

Diperkuat
sumber
1

Melihat jawaban Enhardened, mereka menyatakan bahwa ekspresi kedua dari belakang mereka tidak akan cocok dengan urutan dengan hanya satu karakter di antara mereka. Ada cara mudah untuk memperbaikinya tanpa menggunakan melihat ke depan / melihat ke belakang, yaitu dengan mengganti karakter awal / akhir dengan karakter batas. Ini memungkinkan Anda mencocokkan dengan batas kata yang mencakup awal / akhir. Dengan demikian, ekspresi yang sesuai haruslah:

(?:[^x]|\b)(x{n}|x{m})(?:[^x]|\b)

Seperti yang Anda lihat di sini: https://regex101.com/r/oC5oJ4/2 .

rozza2058
sumber
1
Keren, saya tidak terbiasa dengan cara regex menangani batasan. Satu-satunya masalah dengan metode ini adalah saat Anda menggunakan batas non-standar. Tale a look: regex101.com/r/j0nkeo/1 dan regex101.com/r/4Ix7Dr/1
Ditingkatkan
1
@Enhardened - itu poin yang bagus, tampaknya menjadi masalah dengan beberapa grup yang cocok yang tumpang tindih. Itu adalah situasi di mana Anda perlu melihat ke belakang.
rozza2058
1

Posting yang sangat lama, tapi saya ingin berkontribusi yang mungkin bisa membantu. Saya sudah mencobanya persis seperti yang dinyatakan dalam pertanyaan dan berhasil tetapi ada batasan: Urutan kuantitas itu penting. Pertimbangkan ini:

#[a-f0-9]{6}|#[a-f0-9]{3}

Ini akan menemukan semua kemunculan kode warna hex (panjangnya 3 atau 6 digit). Tapi saat aku membalikkannya seperti ini

#[a-f0-9]{3}|#[a-f0-9]{6}

itu hanya akan menemukan 3 digit atau 3 digit pertama dari 6 digit. Ini memang masuk akal dan seorang ahli Regex mungkin langsung melihatnya, tetapi bagi banyak orang ini mungkin perilaku yang aneh. Ada beberapa fitur Regex tingkat lanjut yang mungkin menghindari jebakan ini terlepas dari urutannya, tetapi tidak semua orang menyukai pola Regex.

DanDan
sumber