регулярное выражение, чтобы соответствовать 1 или два символа в наборе, и убедитесь, что они разные - PullRequest
0 голосов
/ 01 января 2019

Хорошо, банда, вот моя загадка:

Я ищу соответствие строки, используя ванильный JavaScript test(), функцию прототипа RegExp, для проверки входной переменной inp:

/{CONDITION}/.test(inp)

Строка должна удовлетворять следующим условиям:

  • Длина может быть один или два символа.Достаточно просто.

    /^*{1,2}$/.test(inp)
    
  • Это должно быть без учета регистра.Нет проблем.

    /^*{1,2}$/i.test(inp)
    
  • Если только один символ, он должен состоять из только символов [tmbrcl]

    /^[tmblcr]{1}$/i.test(inp)
    
  • Если длина двухсимвольная, первый символ должен быть [tmb] ИЛИ [lcr], а второй должен быть в зависимости от того, какое из первых значений установлено , а не .Хорошо:

    /^([tmblcr]{1})$|^([tmb]{1}[lcr]{1})|^([lcr]{1}[tmb]{1})$/i.test(inp)
    

Примеры:

't'   // Good
'B'   // Good
'Rc'  // Good
'bl'  // Good
'tb'  // bad
'mm'  // Bad
'cC'  // Bad
'BB'  // Bad
'Bob' // Bad
'5'   // Bad
'Ċ'   // Still Bad
'ß'   // Suspiciously Bad
'?'  // Now you're just screwing with me
'上'  // You know what? I don't care if this fails gracefully or not. ^&%* you.

Моя цель здесь - проанализировать пользовательский ввод, который укажет вертикальное и горизонтальное положение ('T'/'M'/'B' представляет'Top'/'Middle'/'Bottom' и 'L'/'C'/'R', представляющие 'Left'/'Center'/'Right' соответственно).Пользователю должно быть разрешено передавать любую перестановку двух группировок, в любом случае, в любом порядке (или только одну, в этом случае другой выводится как значение по умолчанию).

I'mне зациклен на использовании регулярных выражений, но казалось неуклюжим делать что-то вроде (или столь же глупо):

  let errd  = false;
      set1  = 'TMB',
      set2  = 'LCR',
      sets  = set1 + set2;
  if(inp.length === 1 && sets.indexOf(inp) === -1) errd = true;
  else if(inp.length === 2){
      let inpArr = inp.split('');
      errd = (set1.indexOf(inpArr[0]) === set1.indexOf(inpArr[1]) === -1 || set2.indexOf(inpArr[0]) === set2.indexOf(inpArr[1]) === -1);
  }else errd = true;

Поэтому мой вопрос: Неужели нет более изящного способа справиться с этим, чем простовыплевывая каждую перестановку желаемого результата?

/^[SINGLE (S)]$|^[CASE A/B]$|^[CASE B/A]$/i

Я имею в виду, что если бы было три,

/^[S]$|^[AB]$|^[AC]$|^[BC]$|^[BA]$|^[CA]$|^[CB]$|^[ABC]$|^[ACB]$|^[BAC]$|^[BCA]$|^[CAB]$|^[CBA]$/i

или (боги помогают мне), ЧЕТЫРЕ персонажа с подобным набором ограничений?Я относительно новичок в RegEx, и мне интересно, не хватает ли здесь основного принципа.У меня есть рабочее решение (версия "/^[S]|[AB]|[BA]$/"), но действительно ли это ПРАВИЛЬНОЕ?

РЕДАКТИРОВАТЬ

Спасибо за звездный, исчерпывающий ответ, Sweeper!

(Вот рабочий код в контексте, на случай, если он позже кому-нибудь поможет):

orient: function(objQS, rPos='TL', offsetWidth=0, offsetHeight=0)  {
    try{

        // objQS accepts a QuerySelector string or an HTMLElement
        let obj = (typeof(objQS) === 'string') ? document.querySelector(objQS) : objQS;
        console.log('obj', obj, obj.getBoundingClientRect())
        if(null == obj || typeof(obj) !== 'object'){ throw('Invalid Target!'); }
        let objBRC = obj.getBoundingClientRect();

        // rPos accepts TL, T/TC, TR, ML, M/C/MC, MR, BL, B/BC, BR (case- and order-insensitive)
        if(!/^(?:[tmbrcl]|[tmb][rcl]|[rcl][tmb])$/i.test(rPos)){ throw('Invalid orientation specified!'); }

        // Accomodate single-character entry of 'm' or 'c', both taken to mean 'mc' ('m'iddle-'c'enter)
        if(/^[mc]$/i.test(rPos)) { rPos = 'mc'; } 

        // Set default orientation to top-left (tl/lt), meaning we have nothing to do for 't'op or 'l'eft
        let osT = objBRC.y + offsetHeight,                       // Note we add the user-set offsets to our bases
            osL = objBRC.x + offsetWidth;                        // so they carry though to the other options.
        if(/m/i.test(rPos))      { osT += (objBRC.height / 2); } // Adjust vertically for 'm'iddle (top + height/2)
        if(/b/i.test(rPos))      { osT += objBRC.height; }       // Adjust vertically for 'b'ottom (top + height)
        if(/c/i.test(rPos))      { osL += (objBRC.width / 2); }  // Adjust horizontally for 'c'enter (left + width/2)
        if(/r/i.test(rPos))      { osL += objBRC.width; }        // Adjust horizontally for 'r'ight (left + width)

        objBRC.offsetTop  = osT;
        objBRC.offsetLeft = osL;
        this.place(osL, osT);
        console.log('return', 'objBRC:', objBRC)
        return objBRC;
    }catch(e){
        console.group('ERROR DETAILS (Error in callout.orient)');
        console.error('Error details:\n  - ', e);
        console.groupEnd();
        return false;
    }
}

1 Ответ

0 голосов
/ 01 января 2019

Ваше регулярное выражение может быть значительно сокращено до этого:

/^(?:[tmbrcl]|[tmb][rcl]|[rcl][tmb])$/i

, что я считаю достаточно хорошим решением.Он читается довольно четко:

Между началом и концом строки есть три параметра:

  • один из [tmbrcl]
  • один из[tmb] затем один из [rcl]
  • один из [rcl] затем один из [tmb]

На самом деле вам не нужны все эти {1} s.

РЕДАКТИРОВАТЬ:

Я не понял, что вы спрашиваете о случаях с большим количеством комплектов.В этом случае, я думаю, вы должны использовать другой подход.

Один из способов заключается в следующем:

  1. Есть по одному регулярному выражению для каждого из наборов:

    var r1 = /[abc]/i // notice the missing ^ and $ anchors
    var r2 = /[def]/i
    var r3 = /[ghi]/i
    
  2. Поместите их все в массив

    var regexes = [r1, r2, r3]
    
  3. Выполните цикл по массиву и посчитайте, сколько регулярных выражений соответствуют строке

  4. Количество регулярных выражений, соответствующих строке, должно быть равно длине строки.

Обратите внимание, что это предполагает, что ваши множества не пересекаются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...