使用正则表达式进行输入模式验证时出错。

huangapple go评论78阅读模式
英文:

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: /[!@#$%^&amp;*()_+\-=\[\]{};&#39;:&quot;\\|,.&lt;&gt;\/?~]/g

Codepen with example

And the snippet below:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const noSymbolsRegex = /[`!@#$%^&amp;*()_+\-=\[\]{};&#39;:&quot;\\|,.&lt;&gt;\/?~]/g;
const onChange = (event) =&gt; {
  const value = event.target.value;
  const hasError = noSymbolsRegex.test(value);
  console.log(
    `Value =&gt; ${value} \n Has forbidden symblos ? ${hasError ? &quot;YES&quot; : &quot;NO&quot;}`
  );
  if (hasError) {
    console.log(&quot;&lt;&lt; == hasError&quot;);
    document.querySelector(&quot;#my-test-input&quot;).dataset.valid = &quot;false&quot;;
  } else {
    document.querySelector(&quot;#my-test-input&quot;).dataset.valid = &quot;true&quot;;
    console.log(&quot;&lt;&lt; == DOES NOT haveError&quot;);
  }
};
const input = document.querySelector(&quot;#my-test-input&quot;);
input?.addEventListener(&quot;keyup&quot;, onChange);

<!-- language: lang-css -->

input[data-valid=&quot;false&quot;] {
  background-color: red;
}

input[data-valid=&quot;true&quot;] {
  background-color: green;
}

<!-- language: lang-html -->

&lt;label for=&quot;test&quot;&gt;Test input&lt;/label&gt;
&lt;input name=&quot;test &quot; type=&quot;text&quot; id=&quot;my-test-input&quot; data-valid=&quot;true&quot;&gt;

<!-- 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

是的,问题出在正则表达式中。
你可以尝试以下的正则表达式:

/[ `!@#$%^&amp;*()_+\-=\[\]{};&#39;:&quot;\\|,.&lt;&gt;\/?~]/
const noSymbolsRegex = /[ `!@#$%^&amp;*()_+\-=\[\]{};&#39;:&quot;\\|,.&lt;&gt;\/?~]/;
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

/[ `!@#$%^&amp;*()_+\-=\[\]{};&#39;:&quot;\\|,.&lt;&gt;\/?~]/

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const noSymbolsRegex = /[ `!@#$%^&amp;*()_+\-=\[\]{};&#39;:&quot;\\|,.&lt;&gt;\/?~]/;
const onChange = (event) =&gt; {
  const value = event.target.value;
  const hasError = noSymbolsRegex.test(value);
  console.log(
    `Value =&gt; ${value} \n Has forbidden symblos ? ${hasError ? &quot;YES&quot; : &quot;NO&quot;}`
  );
  if (hasError) {
    console.log(&quot;&lt;&lt; == hasError&quot;);
    document.querySelector(&quot;#my-test-input&quot;).dataset.valid = &quot;false&quot;;
  } else {
    document.querySelector(&quot;#my-test-input&quot;).dataset.valid = &quot;true&quot;;
    console.log(&quot;&lt;&lt; == DOES NOT haveError&quot;);
  }
};
const input = document.querySelector(&quot;#my-test-input&quot;);
input?.addEventListener(&quot;keyup&quot;, onChange);

<!-- language: lang-css -->

input[data-valid=&quot;false&quot;] {
  background-color: red;
}

input[data-valid=&quot;true&quot;] {
  background-color: green;
}

<!-- language: lang-html -->

&lt;label for=&quot;test&quot;&gt;Test input&lt;/label&gt;
&lt;input name=&quot;test &quot; type=&quot;text&quot; id=&quot;my-test-input&quot; data-valid=&quot;true&quot;&gt;&lt;/input&gt;

<!-- end snippet -->

答案2

得分: 1

这是一个重构后的正则表达式,使用 _test() 时不需要全局标志。

编辑 2023年3月10日,在 test()exec() JS 函数中使用全局标志 //g 会设置正则表达式对象的 _lastindex_ 成员到最后匹配的位置。这就是为什么多次运行这个正则表达式会导致它在字符串的开头和结束之间反复匹配,其中一个匹配而另一个没有。

const noSymbolsRegex = /[!-\/:-@\[-`{-~]/;

虽然这个正则表达式有效,但你的 onChange 事件处理程序似乎在从上下文菜单粘贴时不会被调用。如果使用键盘快捷键 ctrl-v,它会正常工作。但如果从上下文菜单中粘贴,它不会被调用。

额外信息:[!-\/:-@\[-{-~]匹配这32个码点!"#$%&'()*+,-./:;<=>?@[]^_{|}~,这些码点对应于 [\x21-\x7e](?&lt;![^\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 //gin 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 !&quot;#$%&amp;&#39;()*+,-./:;&lt;=&gt;?@[\]^_`{|}~
These codepoints correspond to [\x21-\x7e](?&lt;![^\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.

huangapple
  • 本文由 发表于 2023年3月10日 01:12:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75687898.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定