【问题标题】:JavaScript replace only executes on complete match of the regex when using groups使用组时,JavaScript 替换仅在正则表达式完全匹配时执行
【发布时间】:2021-04-10 06:20:06
【问题描述】:

我正在尝试使用以下模式创建输入掩码:“4.01.05.01-6”。在 onchange 方法中,我执行了一个使用 replace 方法的函数:

value = value
.replace(/\D/g, '')
.replace(
/^(\d{1})(\d{2})(\d{2})(\d{2})(\d{1})/,
'$1.$2.$3.$4-$5'
)

问题是当我有 8 位数字时,我只在正则表达式完全匹配后才收到被屏蔽的输入值。那不是我想要的。我想输入输入,并且在我输入时掩码将起作用,例如,如果我只是输入“1234”,我想输入值“1.23.4”

OBS: 我不关心以下信息,但我使用的是带有受控输入的 React,这个名为“value”的变量用于创建 setState。

【问题讨论】:

    标签: javascript reactjs regex replace


    【解决方案1】:

    使用可选的非捕获组使正则表达式的所有部分,但第一个部分是可选的。然后,您可以在用作替换参数的回调函数中检查每个可选组是否匹配,并动态构建替换字符串。

    查看 JavaScript 演示:

    function App() {
      const [Version, setVersion] = React.useState('')
      function maskVersion({ target: { value } }) {
        const re  = /^(\d)(?:(\d{1,2})(?:(\d{1,2})(?:(\d{1,2})(\d)?)?)?)?[\w\W]*$/
        setVersion(value.replace(/\D/g,'').replace(re, (_,a,b,c,d,e) =>  
           a + 
            ( b ? `.${b}` : "") + 
             ( c ? `.${c}` : "") + 
              ( d ? `.${d}` : "") + 
               ( e ? `-${e}` : "") ))
      }
      return  <div>
          Text: <input type='text' onChange={maskVersion} value={Version} />
      </div>
    }
    
    ReactDOM.render(<App/>, document.querySelector('#root'))
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <div id="root"></div>

    正则表达式 - 参见 its online demo - 匹配:

    • ^ - 字符串开头
    • (\d) - 捕获组 1 (a):一位数
    • (?:(\d{1,2})(?:(\d{1,2})(?:(\d{1,2})(\d)?)?)?)? - 可选的非捕获组匹配
      • (\d{1,2}) - 捕获组 2 (b):一位或两位数
      • (?:(\d{1,2})(?:(\d{1,2})(\d)?)?)? - 可选的非捕获组匹配
        • (\d{1,2}) - 捕获组 3 (c):一位或两位数
        • (?:(\d{1,2})(\d)?)? - 可选的非捕获组匹配
          • (\d{1,2}) - 捕获组 4 (d):一位或两位数
          • (\d)? - 一个可选的捕获组 5 (e):在数字上
    • [\w\W]* - 任何零个或多个字符(如果输入更多字符,则截断输入字符串)
    • $ - 字符串结束。

    替换是使用三元运算符构建的,如果匹配b,则附加一个点加b值,如果匹配cd,则相同,如果有@987654344 @ 组匹配,添加 -e 组值。

    【讨论】:

    • 您的解决方案有效,但我不太了解它是如何工作的,您能详细解释一下吗?
    • @ThiagoNunesBatista 我添加了更多解释。
    【解决方案2】:

    我想不出任何方法只使用正则表达式。 我认为你应该用输入的长度来判断,所以当输入的长度是 3 位时,然后只像这样运行这些数字的替换

    if(value.length >= 2 && value.length <= 3){
    value.replace(
    /^(\d{1})(\d{1,2})/,
    '$1.$2'
    )
    }
    

    对于数字长度为 4 - 5 等的情况执行相同操作。

    所以整个代码可能是这样的

    if(value.length >= 2 && value.length <= 3){
    value.replace(
    /^(\d{1})(\d{1,2})/,
    '$1.$2'
    )
    }else if(value.length >= 4 && value.length <= 5){
    value.replace(
    /^(\d{1})(\d{2})(\d{1,2})/,
    '$1.$2.$3'
    )
    }else if(value.length >= 6 && value.length <= 7){
    value.replace(
    /^(\d{1})(\d{2})(\d{2})(\d{1,2})/,
    '$1.$2.$3.$4'
    )
    }else if(value.length == 8){
    value.replace(
    /^(\d{1})(\d{2})(\d{2})(\d{2})(\d{1})/,
    '$1.$2.$3.$4-$5'
    )
    }
    

    也许我在上面的代码中有一些错误,但我想你明白了

    【讨论】:

      猜你喜欢
      • 2017-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-10
      • 2015-11-11
      • 1970-01-01
      • 2013-11-23
      • 1970-01-01
      相关资源
      最近更新 更多