I'm trying to create an input mask with the following pattern: "4.01.05.01-6". In the onchange method I execute a function that uses the replace method:
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. 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"
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.
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.
See the JavaScript demo:
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,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})(?:(\d{1,2})(\d)?)?)?
- an optional non-capturing group matching
(\d{1,2})
- Capturing group 3 ( c
): one or two digits (?:(\d{1,2})(\d)?)?
- an optional non-capturing group matching
(\d{1,2})
- Capturing group 4 ( d
): one or two digits (\d)?
- an optional capturing group 5 ( e
): on digit [\w\W]*
- any zero or more chars (to truncate the input string if more chars are typed) $
- 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.
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
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.
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.