英文:
Error on using Regex for input pattern validation
问题
我的问题很简单,但是我不明白发生了什么。
我的情况:
- Vanilla JS 和 HTML
- 一个文本输入框具有onChange事件进行验证。每次按键时,一个正则表达式对其进行分析,如果是特殊字符,则使输入框无效。
- 正则表达式:
/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/g
以下是代码片段:
const noSymbolsRegex = /[`!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/g;
const onChange = (event) => {
const value = event.target.value;
const hasError = noSymbolsRegex.test(value);
console.log(
`Value => ${value} \n Has forbidden symblos ? ${hasError ? "YES" : "NO"}`
);
if (hasError) {
console.log("<< == hasError");
document.querySelector("#my-test-input").dataset.valid = "false";
} else {
document.querySelector("#my-test-input").dataset.valid = "true";
console.log("<< == DOES NOT haveError");
}
};
const input = document.querySelector("#my-test-input");
input?.addEventListener("keyup", onChange);
input[data-valid="false"] {
background-color: red;
}
input[data-valid="true"] {
background-color: green;
}
<label for="test">Test input</label>
<input name="test" type="text" id="my-test-input" data-valid="true">
期望的行为
每次插入特殊字符时,正则表达式都必须对其进行测试并返回其是否有效。
实际行为
- 随机地,但特别是如果输入许多特殊字符,然后开始删除它们,正则表达式测试输入并返回没有特殊字符。
- 按下特殊键如Control或Alt会切换有效/无效状态。
我认为问题出在正则表达式,但我不明白为什么它只有时起作用。
英文:
My problem is so simple and yet, i can't figure out what going on.
My scenario:
- Vanilla JS and HTML
- A text input has an onChange event for validation. Every time you press a key a regex analises it and if its an special char it makes the input invalid.
- Regex:
/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/g
And the snippet below:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const noSymbolsRegex = /[`!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/g;
const onChange = (event) => {
const value = event.target.value;
const hasError = noSymbolsRegex.test(value);
console.log(
`Value => ${value} \n Has forbidden symblos ? ${hasError ? "YES" : "NO"}`
);
if (hasError) {
console.log("<< == hasError");
document.querySelector("#my-test-input").dataset.valid = "false";
} else {
document.querySelector("#my-test-input").dataset.valid = "true";
console.log("<< == DOES NOT haveError");
}
};
const input = document.querySelector("#my-test-input");
input?.addEventListener("keyup", onChange);
<!-- language: lang-css -->
input[data-valid="false"] {
background-color: red;
}
input[data-valid="true"] {
background-color: green;
}
<!-- language: lang-html -->
<label for="test">Test input</label>
<input name="test " type="text" id="my-test-input" data-valid="true">
<!-- end snippet -->
Expected behavior
Every time you insert a special char the regex must test it and return if its valid.
Actual behavior
- Randomly, but specially if you enter many special chars and then begins to erase them, regex test the input and returns that it haven't the special chars.
- Pressing special keys like Control or Alt toggle the valid/invalid state.
I suppose the problem is the regex but i don't understand why it works only some times
答案1
得分: 1
是的,问题出在正则表达式中。
你可以尝试以下的正则表达式:
/[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/
const noSymbolsRegex = /[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/;
const onChange = (event) => {
const value = event.target.value;
const hasError = noSymbolsRegex.test(value);
console.log(
`Value => ${value} \n Has forbidden symblos ? ${hasError ? "YES" : "NO"}`
);
if (hasError) {
console.log("<< == hasError");
document.querySelector("#my-test-input").dataset.valid = "false";
} else {
document.querySelector("#my-test-input").dataset.valid = "true";
console.log("<< == DOES NOT haveError");
}
};
const input = document.querySelector("#my-test-input");
input?.addEventListener("keyup", onChange);
input[data-valid="false"] {
background-color: red;
}
input[data-valid="true"] {
background-color: green;
}
<label for="test">Test input</label>
<input name="test " type="text" id="my-test-input" data-valid="true"></input>
英文:
Yes, problem is in regex
You can try below regex
/[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const noSymbolsRegex = /[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/;
const onChange = (event) => {
const value = event.target.value;
const hasError = noSymbolsRegex.test(value);
console.log(
`Value => ${value} \n Has forbidden symblos ? ${hasError ? "YES" : "NO"}`
);
if (hasError) {
console.log("<< == hasError");
document.querySelector("#my-test-input").dataset.valid = "false";
} else {
document.querySelector("#my-test-input").dataset.valid = "true";
console.log("<< == DOES NOT haveError");
}
};
const input = document.querySelector("#my-test-input");
input?.addEventListener("keyup", onChange);
<!-- language: lang-css -->
input[data-valid="false"] {
background-color: red;
}
input[data-valid="true"] {
background-color: green;
}
<!-- language: lang-html -->
<label for="test">Test input</label>
<input name="test " type="text" id="my-test-input" data-valid="true"></input>
<!-- end snippet -->
答案2
得分: 1
这是一个重构后的正则表达式,使用 _test()
时不需要全局标志。
编辑 2023年3月10日,在 test()
和 exec()
JS 函数中使用全局标志 //g
会设置正则表达式对象的 _lastindex_
成员到最后匹配的位置。这就是为什么多次运行这个正则表达式会导致它在字符串的开头和结束之间反复匹配,其中一个匹配而另一个没有。
const noSymbolsRegex = /[!-\/:-@\[-`{-~]/;
虽然这个正则表达式有效,但你的 onChange
事件处理程序似乎在从上下文菜单粘贴时不会被调用。如果使用键盘快捷键 ctrl-v
,它会正常工作。但如果从上下文菜单中粘贴,它不会被调用。
额外信息:[!-\/:-@\[-
{-~]匹配这32个码点
!"#$%&'()*+,-./:;<=>?@[]^_{|}~
,这些码点对应于 [\x21-\x7e](?<![^\W_])
也是一样的。
有关 JS lastindex
的信息可以在这里找到:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex
摘录:
正则表达式实例的 lastIndex
数据属性指定下一个匹配开始的索引。
只有在正则表达式实例使用 g
标志指示全局搜索,或者使用 y
标志指示粘性搜索时,才会设置此属性。
英文:
This is a refactored regex, and no need for the global flag with test().
Edit 3/10/23, using the global flag //g
in test() and exec() JS functions sets the regex objects lastindex
member to the last matched position.
Thats why the repeated runs of this regex cause it to flip flop the match
from the strings beginning, to the strings end where one matched and the other didn't.
const noSymbolsRegex = /[!-\/:-@\[-`{-~]/;
Works but your onChange event handler doesn't seem to get called on a paste from context menu.
If doing keystrokes ctrl-v works fine. But if from the context menu, doesn't get called.
Extra info [!-\/:-@\[-`{-~]
matches these 32 codepoints !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
These codepoints correspond to [\x21-\x7e](?<![^\W_])
as well.
Info on JS lastindex regex member can be founh here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex
Excerpt:
The lastIndex data property of a RegExp instance specifies the index at
which to start the next match.
This property is set only if the regular expression instance used the g flag
to indicate a global search, or the y flag to indicate a sticky search.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论