Mengonversi string input pengguna ke ekspresi reguler

333

Saya merancang penguji ekspresi reguler dalam HTML dan JavaScript. Pengguna akan memasukkan regex, string, dan memilih fungsi yang ingin mereka uji (mis. Mencari, mencocokkan, mengganti, dll.) Melalui tombol radio dan program akan menampilkan hasil ketika fungsi itu dijalankan dengan argumen yang ditentukan. Tentu akan ada kotak teks tambahan untuk menggantikan argumen tambahan dan semacamnya.

Masalah saya adalah mendapatkan string dari pengguna dan mengubahnya menjadi ekspresi reguler. Jika saya mengatakan bahwa mereka tidak perlu memiliki //sekitar regex yang mereka masukkan, maka mereka tidak dapat mengatur bendera, seperti gdan i. Jadi mereka harus memiliki //sekitar ekspresi, tetapi bagaimana saya bisa mengubah string itu menjadi sebuah regex? Ini tidak bisa menjadi literal karena sebuah string, dan saya tidak bisa meneruskannya ke konstruktor RegExp karena itu bukan string tanpa //'s. Apakah ada cara lain untuk membuat string input pengguna menjadi sebuah regex? Apakah saya harus mengurai string dan bendera regex dengan //'s kemudian membangunnya dengan cara lain? Haruskah saya minta mereka memasukkan string, dan kemudian memasukkan bendera secara terpisah?

Gordon Gustafson
sumber

Jawaban:

611

Gunakan konstruktor objek RegExp untuk membuat ekspresi reguler dari string:

var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;
Gumbo
sumber
1
akan menyenangkan untuk memiliki alat online dengan bidang input
holms
61
Ketika melakukannya dengan cara ini, Anda harus melarikan diri dari garis miring terbalik, misalnyavar re = new RegExp("\\w+");
JD Smith
12
@holms regex101.com juga merupakan alat online regex yang bagus
Fran Herrero
2
Butuh beberapa saat untuk melihat bahwa tidak ada garis miring yang diperlukan
Gerfried
2
@ JDSmith Saya tidak bersungguh-sungguh dalam contoh Anda. Maksud saya, Anda harus lolos dari tanda kutip ganda jika Anda ingin mereka menjadi bagian dari regex asalkan kode itu sulit. Jelas, semua ini tidak berlaku jika string dalam variabel seperti dari <input>tag HTML. var re = new RegExp("\"\\w+\"");adalah contoh dari regex kode keras menggunakan konstruktor RegExp dan melarikan diri dari tanda kutip ganda adalah diperlukan. Apa yang saya maksud dengan string dalam sebuah variabel adalah bahwa Anda hanya dapat melakukan var re = new RegExp(str);dan strmungkin mengandung tanda kutip ganda atau garis miring terbalik tanpa masalah.
Luis Paulo
66
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);

atau

var match = inputstring.match(new RegExp('^/(.*?)/([gimy]*)$'));
// sanity check here
var regex = new RegExp(match[1], match[2]);
Anonim
sumber
Anda harus mempertimbangkan bahwa input seperti yang tidak valid /\/dikenali.
Gumbo
8
Atau biarkan konstruktor RegExp gagal, "tertinggal \ dalam ekspresi reguler", alih-alih menulis parser yang rumit.
Anonim
21

Berikut ini adalah one-liner: str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

Saya mendapatkannya dari modul NPM escape-string-regexp .

Cobalah:

escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
function escapeStringRegExp(str) {
    return str.replace(escapeStringRegExp.matchOperatorsRe, '\\$&');
}

console.log(new RegExp(escapeStringRegExp('example.com')));
// => /example\.com/

Menggunakan literal templat yang ditandai dengan dukungan bendera:

function str2reg(flags = 'u') {
    return (...args) => new RegExp(escapeStringRegExp(evalTemplate(...args))
        , flags)
}

function evalTemplate(strings, ...values) {
    let i = 0
    return strings.reduce((str, string) => `${str}${string}${
        i < values.length ? values[i++] : ''}`, '')
}

console.log(str2reg()`example.com`)
// => /example\.com/u
Rivenfall
sumber
15

Gunakan konstruktor objek JavaScript RegExp .

var re = new RegExp("\\w+");
re.test("hello");

Anda bisa meneruskan flag sebagai argumen string kedua ke konstruktor. Lihat dokumentasi untuk detailnya.

Ayman Hourieh
sumber
9

Dalam kasus saya, input pengguna kadang-kadang dikelilingi oleh pembatas dan terkadang tidak. oleh karena itu saya menambahkan kasus lain ..

var regParts = inputstring.match(/^\/(.*?)\/([gim]*)$/);
if (regParts) {
    // the parsed pattern had delimiters and modifiers. handle them. 
    var regexp = new RegExp(regParts[1], regParts[2]);
} else {
    // we got pattern string without delimiters
    var regexp = new RegExp(inputstring);
}
staabm
sumber
3
Anda selalu bisa menggunakan .split()fungsi alih-alih string regex yang panjang. regParts = inputstring.split('/')ini akan membuat regParts[1]string regex, dan regParts[2]pembatas (dengan asumsi pengaturan regex adalah /.../gim). Anda dapat memeriksa apakah ada pembatas dengan regParts[2].length < 0.
Jaketr00
3

Saya sarankan Anda juga menambahkan kotak centang terpisah atau bidang teks untuk bendera khusus. Dengan begitu jelas bahwa pengguna tidak perlu menambahkan apapun //. Dalam hal penggantian, berikan dua bidang teks. Ini akan membuat hidup Anda jauh lebih mudah.

Mengapa? Karena kalau tidak, beberapa pengguna akan menambahkan //sementara yang lain tidak. Dan beberapa akan membuat kesalahan sintaksis. Kemudian, setelah Anda menghapus //'s, Anda mungkin berakhir dengan regex yang valid secara sintaksis yang tidak seperti apa yang dimaksudkan pengguna, yang mengarah ke perilaku aneh (dari perspektif pengguna).

Stephan202
sumber
2

Ini akan berfungsi juga ketika string tidak valid atau tidak mengandung flag, dll:

function regExpFromString(q) {
  let flags = q.replace(/.*\/([gimuy]*)$/, '$1');
  if (flags === q) flags = '';
  let pattern = (flags ? q.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1') : q);
  try { return new RegExp(pattern, flags); } catch (e) { return null; }
}

console.log(regExpFromString('\\bword\\b'));
console.log(regExpFromString('\/\\bword\\b\/gi'));
            

kofifus
sumber
2

Jika Anda benar - benar ingin mengonversi string menjadi regex, coba gunakan fungsi berikut:

function String2Regex(s){return new RegExp(s.match(/\/(.+)\/.*/)[1], s.match(/\/.+\/(.*)/)[1]);}

Anda dapat menggunakannya seperti ini:

"abc".match(String2Regex("/a/g"))
> ["a"]

Untuk referensi, ini adalah versi yang diformat dan lebih modern:

const String2Regex = str => {
  // Main regex
  const main = str.match(/\/(.+)\/.*/)[1]

  // Regex options
  const options = str.match(/\/.+\/(.*)/)[1]

  // Return compiled regex
  return new RegExp(main, options)
}
Richie Bendall
sumber
1

Berkat jawaban sebelumnya, blok ini berfungsi dengan baik sebagai solusi tujuan umum untuk menerapkan string yang dapat dikonfigurasi ke dalam RegEx .. untuk memfilter teks:

var permittedChars = '^a-z0-9 _,.?!@+<>';
permittedChars = '[' + permittedChars + ']';

var flags = 'gi';
var strFilterRegEx = new RegExp(permittedChars, flags);

log.debug ('strFilterRegEx: ' + strFilterRegEx);

strVal = strVal.replace(strFilterRegEx, '');
// this replaces hard code solt:
// strVal = strVal.replace(/[^a-z0-9 _,.?!@+]/ig, '');
Gene Bo
sumber
1

Anda dapat meminta bendera menggunakan kotak centang lalu melakukan sesuatu seperti ini:

var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);
Pim Jager
sumber
tampak seperti regex hilang Trailing p .. Stack tidak akan membiarkan saya membuat 1 karakter mengedit
Gene Bo
-3

Saya gunakan evaluntuk menyelesaikan masalah ini.

Sebagai contoh:

    function regex_exec() {

        // Important! Like @Samuel Faure mentioned, Eval on user input is a crazy security risk, so before use this method, please take care of the security risk. 
        var regex = $("#regex").val();

        // eval()
        var patt = eval(userInput);

        $("#result").val(patt.exec($("#textContent").val()));
    }
Playhi
sumber
3
eval pada userInput adalah risiko keamanan yang gila
Samuel Faure
1
Tuan bobby tables!
Luiz Felipe