Kullanıcı giriş dizesini normal ifadeye dönüştürme


333

HTML ve JavaScript'te düzenli bir ifade test cihazı tasarlıyorum. Kullanıcı bir normal ifade, bir dize girecek ve radyo düğmesi ile test etmek istediği işlevi (ör. Arama, eşleme, değiştirme vb.) Seçecek ve bu işlev belirtilen bağımsız değişkenlerle çalıştırıldığında program sonuçları görüntüleyecektir. Doğal olarak, ekstra argümanların yerini alacak ek metin kutuları olacaktır.

Benim sorunum dize kullanıcıdan alıp normal bir ifadeye dönüştürmektir. Eğer girdikleri //normal ifade etrafında olmaları gerekmediğini söylersem, gve gibi bayraklar ayarlayamazlar i. Yani //ifadenin etrafında 's olması gerekir , ama bu dizeyi normal ifadeye nasıl dönüştürebilirim? Onun bir dize beri bir değişmez olamaz, ve RegExp yapıcısına //'s olmadan bir dize beri geçemez . Bir regex kullanıcı giriş dizesi yapmak için başka bir yolu var mı? Normal ifadenin dize ve bayrakları //'s ile ayrıştırmak zorunda kalacak daha sonra başka bir şekilde inşa etmek? Onları bir dize girmeli ve sonra bayrakları ayrı ayrı girmeli miyim?

Yanıtlar:


611

Bir dizeden normal bir ifade oluşturmak için RegExp nesne yapıcısını kullanın:

var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;

1
bir giriş alanı ile çevrimiçi bir araç olması güzel olurdu
holms

61
Bu şekilde yaparken, ters eğik çizgiden kaçmanız gerekir, örn.var re = new RegExp("\\w+");
JD Smith

12
@holms regex101.com da harika bir regex çevrimiçi aracıdır
Fran Herrero

2
Sonunda eğik çizgi olmaması gerektiğini görmek
biraz zamanımı aldı

2
@JDSmith Örneğinizde bunu kastetmemiştim. Ben sert kodlanmış olması koşuluyla regex bir parçası olmasını istiyorsanız çift tırnak kaçmak gerekiyordu. Açıkça, dize bir <input>HTML etiketindeki gibi bir değişkendeyse bunların hiçbiri geçerli değildir . var re = new RegExp("\"\\w+\"");RegExp kurucu kullanılarak bir sabit kodlanmış düzenli ifade örneğidir ve çift tırnak kaçan olup gerekli. Ne bir değişken bir dize ile kastedilen yapmak var re = new RegExp(str);ve sadece strçift ​​tırnak veya ters eğik çizgi sorunsuz içerebilir.
Luis Paulo

66
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);

veya

var match = inputstring.match(new RegExp('^/(.*?)/([gimy]*)$'));
// sanity check here
var regex = new RegExp(match[1], match[2]);

Gibi geçersiz bir girdinin /\/tanındığını düşünmelisiniz .
Gumbo

8
Ya da RegExp yapıcısının karmaşık bir çözümleyici yazmak yerine "normal ifadede" izleyen "başarısız olmasına izin verin.
İsimsiz

21

İşte bir astar: str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

Escape-string-regexp NPM modülünden aldım .

Denemek:

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

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

Etiketli şablon değişmezlerini bayrak desteği ile kullanma:

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


9

Benim durumumda kullanıcı girişi bazen sınırlayıcılar tarafından çevrelenmiş ve bazen değil. bu yüzden başka bir dava ekledim ..

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);
}

3
.split()uzun bir normal ifade dizesi yerine her zaman işlevi kullanabilirsiniz . regParts = inputstring.split('/')bu regParts[1], normal ifade dizesini ve regParts[2]sınırlayıcıları (normal ifade kurulumunun olduğu varsayılarak /.../gim) yapar. İle sınırlayıcı olup olmadığını kontrol edebilirsiniz regParts[2].length < 0.
Jaketr00

3

Ayrıca özel bayraklar için ayrı onay kutuları veya metin alanı eklemenizi öneririm. Bu şekilde kullanıcının herhangi bir şey eklemesine gerek olmadığı açıktır //. Değiştirme durumunda iki metin alanı sağlayın . Bu hayatınızı daha kolay hale getirecektir.

Neden? Aksi takdirde bazı kullanıcılar ekleyecek, bazıları ise eklemeyecektir //. Ve bazıları sözdizimi hatası verir. Ardından, //'leri soyduktan sonra , kullanıcının istediği gibi olmayan ve kullanıcının bakış açısından garip davranışa yol açan sözdizimsel olarak geçerli bir normal ifade ile karşılaşabilirsiniz.


2

Bu, dize geçersiz olduğunda veya bayraklar vb. İçermediğinde de çalışır:

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'));
            


2

Eğer varsa gerçekten bir regex için bir dize dönüştürmek istediğiniz, aşağıdaki işlevi kullanmayı deneyin:

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

Şöyle kullanabilirsiniz:

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

Referans olarak, biçimlendirilmiş ve daha modern bir sürüm:

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)
}

1

Daha önceki yanıtlar sayesinde, bu bloklar, metni filtrelemek için bir RegEx'e yapılandırılabilir bir dize uygulamak için genel amaçlı bir çözüm olarak hizmet eder:

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, '');

1

Onay kutularını kullanarak bayraklar isteyebilir ve ardından böyle bir şey yapabilirsiniz:

var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);

RegEx izleyen p eksik gibi görünüyor .. Yığın bana 1 karakter düzenleme yapmama izin vermedi
Gene Bo

-3

evalBu sorunu çözmek için kullanıyorum .

Örneğin:

    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()));
    }

3
userInput için değerlendirme çılgın bir güvenlik riskidir
Samuel Faure

1
bay bobby tabloları!
Luiz Felipe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.