2

好的帮派,这是我的难题:

我正在寻找使用原型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;
    }
}
4

1 回答 1

2

您的正则表达式可以大大缩短为:

/^(?:[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. 匹配字符串的正则表达式的数量应该等于字符串的长度。

请注意,这假设您的集合不相交。

于 2019-01-01T01:23:01.313 回答