Bagaimana cara "pencocokan terbalik" dengan regex?

112

Saya menggunakan RegexBuddy tetapi saya bermasalah dengan hal ini: \

Saya sedang memproses file baris demi baris. Saya membangun "model garis" agar sesuai dengan yang saya inginkan.

Sekarang saya ingin melakukan pencocokan terbalik ... yaitu saya ingin mencocokkan baris di mana terdapat rangkaian 6 huruf, tetapi hanya jika enam huruf ini bukan Andrea , bagaimana saya harus melakukannya?


EDIT: Saya akan menulis program yang menggunakan regex ini, saya belum tahu apakah di python atau php, saya melakukan hal ini terlebih dahulu untuk mempelajari beberapa regex :) Ada berbagai jenis baris, saya ingin menggunakan regex untuk memilih jenis yang saya minati. Setelah saya mendapatkan baris ini, saya harus menerapkan filter lain hanya agar tidak cocok dengan nilai yang diketahui, saya memerlukan yang lainnya, bukan itu. (?! Tidak diinginkan) bekerja dengan baik, terima kasih. :-)

Saya harap ini menjelaskan pertanyaannya :)

Andrea Ambu
sumber
Sebenarnya sepertinya Anda mungkin melakukan lebih baik untuk memberi kami sedikit lebih banyak informasi tentang apa yang Anda lakukan, dan lihat apakah seseorang dapat menawarkan solusi alternatif. Biasanya, mencoba mengurai seluruh file dengan membuat ekspresi reguler yang cocok dengan setiap baris adalah rute yang agak rumit :)
Dan

Jawaban:

70
(?!Andrea).{6}

Dengan asumsi mesin regexp Anda mendukung lookahead negatif ..

Sunting: ..atau mungkin Anda lebih suka menggunakan [A-Za-z]{6}sebagai pengganti.{6}

Edit (lagi): Perhatikan bahwa lookahead dan lookbehind biasanya bukan cara yang tepat untuk "membalik" pencocokan ekspresi reguler. Regexps tidak benar-benar disiapkan untuk melakukan pencocokan negatif, mereka menyerahkannya ke bahasa apa pun yang Anda gunakan.

Dan
sumber
Anda perlu menambahkan ^ yang digunakan @Vinko Vrsalovic agar tidak cocok dengan "ndrea \ n"
bdukes
2
. tidak cocok \ n secara default (beberapa bahasa [misalnya Perl] memungkinkan Anda untuk mengaktifkan perilaku itu, tetapi secara default. cocok dengan semuanya TAPI \ n).
Dan
1
(ditambah, OP tidak pernah menyebutkan string harus terjadi di awal baris)
Dan
1
apa maksudmu untuk OP?
Andrea Ambu
1
Andrea: OP berarti "poster asli", jadi, saya mengacu pada Anda :)
Dan
47

Untuk Python / Java,

^(.(?!(some text)))*$

http://www.lisnichenko.com/articles/javapython-inverse-regex.html

Dmytro
sumber
4
Ini tidak berhasil. Anda sedang memikirkan idiom Tempered Greedy Token. tapi titik itu harus berada di belakang kepala yang terlihat, bukan sebelumnya. Lihat pertanyaan ini . Tapi pendekatan itu berlebihan untuk tugas ini.
Alan Moore
Tidak tahu dalam bahasa mana itu ditulis, tetapi berfungsi seperti pesona dalam teks Sublim untuk membersihkan data pengujian saya. Terima kasih!
Matthias dirickx
1
@AlanMoore Sebenarnya, ini hampir akan berhasil untuk kasus penggunaan ini. Namun, jika some textmemulai baris, itu akan mengembalikan hasil yang salah.
Zenexer
2
@ Zenexer, itulah yang saya maksud. Jika titik tersebut berada setelah lookahead, bukan sebelumnya, ini berfungsi dengan sempurna.
Alan Moore
Berikut ini tautan yang menjelaskan lebih lanjut. Saya tidak mengerti mengapa ?!dan tidak adil !.
Timo
21

Diperbarui dengan umpan balik dari Alan Moore

Di PCRE dan varian serupa, Anda sebenarnya dapat membuat regex yang cocok dengan baris mana pun yang tidak berisi nilai:

^(?:(?!Andrea).)*$

Ini disebut token rakus yang marah . Sisi negatifnya adalah kinerjanya tidak baik.

Zenexer
sumber
1
Ini adalah Token Keserakahan Tempered dalam bentuk panjang. Hanya menempatkan titik (atau [\s\S], yang hanya berguna dalam JavaScript) setelah lookahead kedua, dan Anda tidak perlu yang pertama: ^(?:(?!Andrea).)*$.
Alan Moore
@Alanoore Bagus! Saya tidak dapat menemukan pola mapan yang bekerja seperti itu, jadi saya membuat sendiri. Daripada saya mengambil jawaban Anda, Anda harus memberikan itu sebagai milik Anda.
Zenexer
Tidak apa-apa, sudah ada banyak jawaban bagus. Dan Anda berhak mendapatkan pujian karena menemukan idiom Anda sendiri. Bersulang!
Alan Moore
Mengapa Anda menyarankan untuk menggunakan [\S\s]? OP berbicara tentang baris yang cocok, tidak mengandung kata "Andrea". Bukan tentang memeriksa apakah seluruh string mengandung kata ini. Apakah saya melewatkan sesuatu?
x-yuri
@ x-yuri Saya pikir Anda benar. Saya mungkin menjawab pertanyaan yang saya miliki adalah saya pertama kali mengunjungi halaman ini, mengabaikan perbedaannya. Namun, koneksi saya tidak cukup baik untuk memperbarui jawabannya saat ini (<10 kbps)
Zenexer
11

Bahasa apa yang Anda gunakan? Kemampuan dan sintaks dari implementasi regex penting untuk ini.

Anda bisa menggunakan lihat ke depan. Menggunakan python sebagai contoh

import re

not_andrea = re.compile('(?!Andrea)\w{6}', re.IGNORECASE)

Untuk memecahnya:

(?! Andrea) berarti 'cocok jika 6 karakter berikutnya bukan "Andrea"'; jika demikian maka

\ w berarti "karakter kata" - karakter alfanumerik. Ini setara dengan kelas [a-zA-Z0-9_]

\ w {6} artinya tepat 6 karakter kata.

re.IGNORECASE berarti Anda akan mengecualikan "Andrea", "andrea", "ANDREA" ...

Cara lain adalah dengan menggunakan logika program Anda - gunakan semua baris yang tidak cocok dengan Andrea dan letakkan di regex kedua untuk memeriksa 6 karakter. Atau periksa dulu setidaknya 6 karakter kata, lalu periksa apakah kata itu tidak cocok dengan Andrea.

Hamish Downer
sumber
7

Penegasan lookahead negatif

(?!Andrea)

Ini sebenarnya bukan pencocokan terbalik, tetapi ini yang terbaik yang dapat Anda lakukan secara langsung dengan regex. Tidak semua platform mendukungnya.

Vinko Vrsalovic
sumber
1
Sampai penanya menjelaskan, saya tidak melihat bahwa pertandingan harus dimulai di awal baris. Jadi mengapa ^?
Hamish Downer
Karena saya mengerti dia ingin memeriksa di awal baris, diedit diberikan klarifikasi
Vinko Vrsalovic
5

Jika Anda ingin melakukan ini di RegexBuddy, ada dua cara untuk mendapatkan daftar semua baris yang tidak cocok dengan regex.

Pada toolbar di panel Test, setel cakupan pengujian ke "Baris demi baris". Ketika Anda melakukan itu, item Daftar Semua Garis tanpa Kecocokan akan muncul di bawah tombol Daftar Semua pada toolbar yang sama. (Jika Anda tidak melihat tombol Daftar Semua, klik tombol Cocokkan di toolbar utama.)

Pada panel GREP, Anda dapat mengaktifkan kotak centang "berbasis garis" dan "membalikkan hasil" untuk mendapatkan daftar baris yang tidak cocok dalam file yang Anda telusuri.

Jan Goyvaerts
sumber
5

(?!berguna dalam praktik. Meskipun secara tegas, melihat ke depan bukanlah ekspresi reguler seperti yang didefinisikan secara matematis.

Anda dapat menulis ekspresi reguler terbalik secara manual.

Berikut adalah program untuk menghitung hasil secara otomatis. Hasilnya adalah hasil mesin, yang biasanya jauh lebih kompleks daripada tulisan tangan. Tapi hasilnya berhasil.

lemah
sumber
1

Saya baru saja menemukan metode ini yang mungkin intensif perangkat keras tetapi berfungsi:

Anda dapat mengganti semua karakter yang cocok dengan regex dengan string kosong.

Ini adalah satu perjalanan:

notMatched = re.sub(regex, "", string)

Saya menggunakan ini karena saya terpaksa menggunakan regex yang sangat kompleks dan tidak tahu cara membalikkan setiap bagiannya dalam waktu yang wajar.

Ini hanya akan mengembalikan Anda hasil string, bukan objek yang cocok!

Matthias Herrmann
sumber
-3

Dalam perl Anda bisa melakukannya

proses ($ baris) if ($ line = ~! / Andrea /);

phreakre
sumber
4
Sintaks itu salah. Saya pikir yang Anda maksud adalah proses ($ line) jika $ line! ~ / Andrea /
dland