Регулярное выражение, чтобы соответствовать 1 или два символа в наборе, и убедитесь, что они разные
Ладно, банда, вот моя загадка:
Я ищу соответствие строки, используя ванильный 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'
соответственно). Пользователю должно быть разрешено передавать любую перестановку двух группировок, в любом случае, в любом порядке (или только одну, в этом случае другой выводится по умолчанию).
Я не зациклен на использовании регулярных выражений, но это казалось неуклюжим делать что-то вроде (или столь же тупое):
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 ответ
Ваше регулярное выражение может быть значительно сокращено до этого:
/^(?:[tmbrcl]|[tmb][rcl]|[rcl][tmb])$/i
который я считаю достаточно хорошим решением. Это читается довольно ясно:
Между началом и концом строки есть три варианта:
- один из
[tmbrcl]
- один из
[tmb]
затем один из[rcl]
- один из
[rcl]
затем один из[tmb]
Вам на самом деле не нужны все эти {1}
s.
РЕДАКТИРОВАТЬ:
Я не понял, что вы спрашиваете о случаях с большим количеством комплектов. В этом случае, я думаю, вы должны использовать другой подход.
Одним из способов является это:
Есть одно регулярное выражение для каждого из наборов:
var r1 = /[abc]/i // notice the missing ^ and $ anchors var r2 = /[def]/i var r3 = /[ghi]/i
Поместите их все в массив
var regexes = [r1, r2, r3]
Переберите массив и посчитайте, сколько регулярных выражений соответствуют строке
- Количество регулярных выражений, соответствующих строке, должно быть равно длине строки.
Обратите внимание, что это предполагает, что ваши множества не пересекаются.