简体   繁体   English

JavaScript 替换仅在使用组时在正则表达式的完全匹配时执行

[英]JavaScript replace only executes on complete match of the regex when using groups

I'm trying to create an input mask with the following pattern: "4.01.05.01-6".我正在尝试使用以下模式创建输入掩码:“4.01.05.01-6”。 In the onchange method I execute a function that uses the replace method:在 onchange 方法中,我执行了一个使用 replace 方法的 function:

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

The problem is that I only receive the masked input value after the regex is fully matched, when I have the 8 digits.问题是,当我有 8 位数字时,正则表达式完全匹配后,我才收到屏蔽的输入值。 That's not what I want.那不是我想要的。 I'd like to type in the input and the mask will be working while I'm typing, for example, if I just typed "1234" I'd like to have the value "1.23.4"我想输入输入,并且在我输入时掩码将起作用,例如,如果我只是输入“1234”,我想输入值“1.23.4”

OBS: I don't the following info matters, but I'm using React with a controlled Input, this variable called "value" is used to make the setState. OBS:我不关心以下信息,但我正在使用带有受控输入的 React,这个名为“value”的变量用于创建 setState。

Make all parts of the regex but the first one optional using an optional non-capturing group.使用可选的非捕获组使正则表达式的所有部分,但第一个部分是可选的。 Then, you can check if each optional group matched in a callback function used as the replacement argument, and build the replacement string dynamically.然后,您可以在用作替换参数的回调 function 中检查每个可选组是否匹配,并动态构建替换字符串。

See the JavaScript demo:请参阅 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>

The regex - see its online demo - matches:正则表达式 - 查看其在线演示- 匹配:

  • ^ - start of string ^ - 字符串的开头
  • (\d) - Capturing group 1 ( a ): one digit (\d) - 捕获组 1 ( a ):一位
  • (?:(\d{1,2})(?:(\d{1,2})(?:(\d{1,2})(\d)?)?)?)? - an optional non-capturing group matching - 一个可选的非捕获组匹配
    • (\d{1,2}) - Capturing group 2 ( b ): one or two digits (\d{1,2}) - 捕获组 2 ( b ):一位或两位数
    • (?:(\d{1,2})(?:(\d{1,2})(\d)?)?)? - an optional non-capturing group matching - 一个可选的非捕获组匹配
      • (\d{1,2}) - Capturing group 3 ( c ): one or two digits (\d{1,2}) - 捕获组 3 ( c ):一位或两位数
      • (?:(\d{1,2})(\d)?)? - an optional non-capturing group matching - 一个可选的非捕获组匹配
        • (\d{1,2}) - Capturing group 4 ( d ): one or two digits (\d{1,2}) - 捕获组 4 ( d ):一位或两位数
        • (\d)? - an optional capturing group 5 ( e ): on digit - 一个可选的捕获组 5 ( e ): on digit
  • [\w\W]* - any zero or more chars (to truncate the input string if more chars are typed) [\w\W]* - 任何零个或多个字符(如果键入更多字符,则截断输入字符串)
  • $ - end of string. $ - 字符串结束。

The replacement is built using the ternary operator, if b is matched, a dot plus b value is appended, if c or d is matched, the same happens, and if there is e group match, a - and the e group value is added.替换是使用三元运算符构建的,如果b匹配,则附加一个点加b值,如果匹配cd ,同样发生,如果有e组匹配,a -e组值.

I can't think of any way doing it with regex only.我想不出任何办法只用正则表达式。 I think you should make cases with the length of the input so when the input is, lets say, 3 digits long, then run the replace for these digits only like this我认为你应该用输入的长度来判断,所以当输入的长度是 3 位时,然后只像这样运行这些数字的替换

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

Do the same for cases of digit length 4 - 5 etc.对数字长度为 4 - 5 等的情况执行相同操作。

So the whole code could be like this所以整个代码可能是这样的

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'
)
}

Maybe i have some errors in the above code but i think you got the idea也许我在上面的代码中有一些错误,但我认为你明白了

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM