好的帮派,这是我的难题:
我正在寻找使用原型test()
的函数vanilla JavaScript 匹配字符串RegExp
来测试输入变量inp
:
/{CONDITION}/.test(inp)
字符串必须满足以下条件:
它可以是一个或两个字符长。很容易。
/^*{1,2}$/.test(inp)
它必须不区分大小写。没问题。
/^*{1,2}$/i.test(inp)
如果只有单个字符,则必须仅由字符组成
[tmbrcl]
/^[tmblcr]{1}$/i.test(inp)
如果两个字符长,第一个字符必须是
[tmb]
OR ,第二个字符必须是第一个不是[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; } }