Bagaimana cara mencocokkan "apa saja hingga urutan karakter ini" dalam ekspresi reguler?

515

Ambil ekspresi reguler ini: /^[^abc]/. Ini akan cocok dengan karakter tunggal apa pun di awal string, kecuali a, b, atau c.

Jika Anda menambahkan *setelahnya - /^[^abc]*/- ekspresi reguler akan terus menambahkan setiap karakter berikutnya ke hasilnya, hingga memenuhi salah satu a, atau b , atau c .

Misalnya, dengan string sumber "qwerty qwerty whatever abc hello", ekspresi akan cocok dengan "qwerty qwerty wh".

Tetapi bagaimana jika saya ingin string yang cocok menjadi "qwerty qwerty whatever "

... Dengan kata lain, bagaimana saya bisa mencocokkan semuanya hingga (tetapi tidak termasuk) urutan yang tepat "abc" ?

callum
sumber
Apa maksudmu match but not including?
Toto
5
Maksud saya, saya ingin mencocokkan "qwerty qwerty whatever "- tidak termasuk "abc". Dengan kata lain, saya tidak ingin pertandingan yang dihasilkan terjadi "qwerty qwerty whatever abc".
callum
2
Dalam javascript Anda bisa saja do string.split('abc')[0]. Tentu bukan jawaban resmi untuk masalah ini, tapi saya merasa lebih mudah daripada regex.
Wylliam Judd

Jawaban:

1022

Anda tidak menentukan rasa regex mana yang Anda gunakan, tetapi ini akan bekerja pada salah satu yang paling populer yang dapat dianggap "lengkap".

/.+?(?=abc)/

Bagaimana itu bekerja

Bagian .+? ini adalah versi tidak serakah dari .+ (satu atau lebih dari apa pun). Saat kami gunakan .+, mesin pada dasarnya akan cocok dengan semuanya. Kemudian, jika ada sesuatu yang lain di regex itu akan kembali dalam langkah-langkah yang mencoba mencocokkan bagian berikut. Ini adalah perilaku serakah , yang berarti sebanyak mungkin memuaskan .

Saat menggunakan .+?, alih-alih mencocokkan semuanya sekaligus dan kembali ke kondisi lain (jika ada), mesin akan mencocokkan karakter berikutnya secara bertahap hingga bagian regex berikutnya dicocokkan (lagi jika ada). Ini adalah yang serakah , artinya cocok dengan sesedikit mungkin untuk memuaskan .

/.+X/  ~ "abcXabcXabcX"        /.+/  ~ "abcXabcXabcX"
          ^^^^^^^^^^^^                  ^^^^^^^^^^^^

/.+?X/ ~ "abcXabcXabcX"        /.+?/ ~ "abcXabcXabcX"
          ^^^^                          ^

Setelah itu kita miliki , pernyataan nol lebar , melihat-lihat . Konstruksi yang dikelompokkan ini cocok dengan isinya, tetapi tidak dihitung sebagai karakter yang cocok ( lebar nol ). Itu hanya kembali jika itu cocok atau tidak ( pernyataan ).(?={contents})

Dengan demikian, dalam istilah lain, regex /.+?(?=abc)/berarti:

Cocokkan karakter apa saja sesedikit mungkin hingga "abc" ditemukan, tanpa menghitung "abc".

sidyll
sumber
12
Ini mungkin tidak akan bekerja dengan jeda baris, jika mereka seharusnya ditangkap.
einord
3
Apa perbedaan antara .+?dan .*?
robbie
4
@ robbie0630 +berarti 1 atau lebih, di mana *berarti 0 atau lebih. Dimasukkan / dikecualikannya ?akan membuatnya serakah atau tidak serakah.
jinglesthula
2
@ testerjoe2 /.+?(?=abc|xyz)/
JohnWrensby
4
Saya perhatikan bahwa ini gagal untuk memilih apa pun jika pola yang Anda cari tidak ada, sebaliknya jika Anda menggunakan ^(?:(?!abc)(?!def).)*Anda dapat rantai untuk mengecualikan pola yang tidak Anda inginkan dan itu akan tetap mengambil semua yang diperlukan bahkan jika pola itu tidak ada
Karan Shishoo
123

Jika Anda ingin menangkap semuanya hingga "abc":

/^(.*?)abc/

Penjelasan:

( )menangkap ekspresi dalam kurung untuk akses menggunakan $1, $2, dll

^ cocokkan mulai dari garis

.*cocok dengan apa pun, ?tidak rakus (cocok dengan jumlah minimum karakter yang diperlukan) - [1]

[1] Alasan mengapa ini diperlukan adalah bahwa jika tidak, dalam string berikut:

whatever whatever something abc something abc

secara default, regex serakah , artinya akan serasi sebanyak mungkin. Oleh karena itu /^.*abc/akan cocok dengan "apa pun apa pun sesuatu sesuatu". Menambahkan quantifier yang tidak rakus ?membuat regex hanya cocok dengan "apa pun apa pun sesuatu".

Jared Ng
sumber
4
Terima kasih, tetapi abc Anda termasuk dalam pertandingan. Dengan kata lain pertandingan yang dihasilkan adalah "apa pun yang sesuatu abc".
callum
1
Bisakah Anda menjelaskan apa yang akhirnya Anda coba lakukan? Jika skenario Anda adalah: (A) Anda ingin semua yang mengarah ke "abc" - cukup gunakan tanda kurung di sekitar apa yang ingin Anda tangkap. (B) Anda ingin mencocokkan string dengan "abc" - Anda harus tetap memeriksa abc, jadi bagaimanapun juga harus menjadi bagian dari regex. Bagaimana lagi Anda dapat memeriksa bahwa itu ada di sana?
Jared Ng
sedtampaknya tidak mendukung pencocokan non-serakah, juga tidak mendukung look-around ( (?=...)). Apa lagi yang bisa saya lakukan? Contoh perintah: echo "ONE: two,three, FOUR FIVE, six,seven" | sed -n -r "s/^ONE: (.+?), .*/\1/p"kembali two,three, FOUR FIVE, tapi saya harapkan two,three...
CodeManX
1
@CoDEmanX Anda mungkin harus mempostingnya sebagai pertanyaan Anda sendiri dan bukan sebagai komentar, terutama karena ini khusus tentang sed. Yang sedang berkata, untuk menjawab pertanyaan Anda: Anda mungkin ingin melihat jawaban untuk pertanyaan ini . Perhatikan juga bahwa dalam contoh Anda, penerjemah yang tidak tamak akan kembali dengan adil two, bukan two,three.
Jared Ng
3
Ini adalah bagaimana SETIAP jawaban regexp akan terlihat - contoh dan penjelasan dari semua bagian ...
jave.web
54

Seperti yang ditunjukkan oleh Jared Ng dan @Issun, kunci untuk menyelesaikan RegEx seperti "mencocokkan semuanya dengan kata atau substring tertentu" atau "mencocokkan semuanya setelah kata atau substring tertentu" disebut "lookaround" pernyataan panjang nol . Baca lebih banyak tentang mereka disini.

Dalam kasus khusus Anda, itu dapat diselesaikan dengan pandangan positif ke depan: .+?(?=abc)

Sebuah gambar bernilai ribuan kata. Lihat penjelasan detail di tangkapan layar.

Screenshot Regex101

Devy
sumber
23
.+?(?=abc)copy-pastable regex lebih berharga.
Tom
Bagaimana dengan mengecualikan ruang utama?
Royi
8

Yang Anda butuhkan adalah melihat-lihat seperti pernyataan .+? (?=abc).

Lihat: Lookahead dan Lookbehind Zero-Length Assertions

Sadarilah bahwa [abc]tidak sama dengan abc. Di dalam kurung itu bukan string - setiap karakter hanyalah salah satu dari kemungkinan. Di luar kurung itu menjadi tali.

aevanko
sumber
7

Untuk regex di Jawa, dan saya percaya juga pada sebagian besar mesin regex, jika Anda ingin memasukkan bagian terakhir ini akan berfungsi:

.+?(abc)

Misalnya, di baris ini:

I have this very nice senabctence

pilih semua karakter hingga "abc" dan sertakan juga abc

menggunakan regex kami, hasilnya adalah: I have this very nice senabc

Uji ini: https://regex101.com/r/mX51ru/1

Dadan
sumber
4

Saya mengakhiri pertanyaan stackoverflow ini setelah mencari bantuan untuk menyelesaikan masalah saya tetapi tidak menemukan solusi untuk itu :(

Jadi saya harus berimprovisasi ... setelah beberapa waktu saya berhasil mencapai regex yang saya butuhkan:

masukkan deskripsi gambar di sini

Seperti yang Anda lihat, saya memerlukan satu folder di depan folder "grp-bps", tanpa menyertakan tanda hubung terakhir. Dan itu diperlukan untuk memiliki setidaknya satu folder setelah folder "grp-bps".

Edit

Versi teks untuk salin-rekat (ubah 'grp-bps' untuk teks Anda):

.*\/grp-bps\/[^\/]+
Loaderon
sumber
6
Tidak ada versi teks? 🙄
kiradotee
2

Ini masuk akal tentang regex.

  1. Kata yang tepat dapat diperoleh dari perintah regex berikut:

("(. *?)") / g

Di sini, kita bisa mendapatkan kata yang tepat secara global yang termasuk dalam tanda kutip ganda. Sebagai Contoh, Jika teks pencarian kami adalah,

Ini adalah contoh untuk kata-kata "dikutip ganda"

maka kita akan mendapatkan "double quote" dari kalimat itu.

Ponmurugan Mohanraj
sumber
Selamat datang di StackOverflow dan terima kasih atas upaya Anda untuk membantu. Namun saya merasa sulit untuk melihat bagaimana ini membantu tujuan yang dinyatakan dalam pertanyaan. Bisakah Anda menguraikan? Bisakah Anda menerapkannya pada contoh yang diberikan? Anda tampaknya fokus pada penanganan ", yang bagi saya tampaknya tidak relevan untuk pertanyaan itu.
Yunnosch
1
Hai, saya telah menjelaskan bagaimana cara mendapatkan kata atau kalimat di antara karakter khusus. Di sini pertanyaan kita juga "apa saja sampai urutan karakter khusus". jadi saya mencoba dengan tanda kutip ganda dan menjelaskannya di sini. Terima kasih.
Ponmurugan Mohanraj
2

Dengan python:

.+?(?=abc) bekerja untuk kasing tunggal.

[^]+?(?=abc)tidak berfungsi, karena python tidak mengenali [^] sebagai regex yang valid. Agar pencocokan multiline berfungsi, Anda harus menggunakan opsi re.DOTALL, misalnya:

re.findall('.+?(?=abc)', data, re.DOTALL)
David Mulder
sumber
0

Saya yakin Anda membutuhkan subekspresi. Jika saya ingat benar, Anda dapat menggunakan ()tanda kurung normal untuk subekspresi.

Bagian ini adalah Dari grep manual:

 Back References and Subexpressions
       The back-reference \n, where n is a single digit, matches the substring
       previously matched  by  the  nth  parenthesized  subexpression  of  the
       regular expression.

Lakukan sesuatu seperti ^[^(abc)]seharusnya melakukan trik.

Nandhini Anand
sumber
Maaf, itu tidak berhasil. Menempatkan abc di dalam tanda kurung sepertinya tidak ada bedanya. Mereka masih diperlakukan sebagai "a ATAU b ATAU c".
callum
-1

Ini $menandai akhir dari sebuah string, jadi sesuatu seperti ini harus berfungsi: di [[^abc]*]$mana Anda mencari sesuatu yang TIDAK AKAN BERAKHIR dalam iterasi apa pun abc, tetapi itu harus berada di akhir

Juga jika Anda menggunakan bahasa skrip dengan regex (seperti php atau js), mereka memiliki fungsi pencarian yang berhenti ketika pertama kali menemukan suatu pola (dan Anda dapat menentukan mulai dari kiri atau mulai dari kanan, atau dengan php, Anda dapat melakukan implode untuk mencerminkan string).

Jacobs
sumber
-6

coba ini

.+?efg

Pertanyaan:

select REGEXP_REPLACE ('abcdefghijklmn','.+?efg', '') FROM dual;

keluaran:

hijklmn
Balakrishna Gondesi
sumber