首页 > 解决方案 > 如何检查输入字段是否包含有效文本而不是表单中的随机字符?

问题描述

我想验证订阅者是否在表单中输入了有意义的英文文本,而不是随机字符,例如“jaghdjagqfsg”。

对于“废话”,我只是指随机字符、仅点/数字/空格、四个或更多辅音等。我只是在寻找不重新发明轮子的食谱或正则表达式模式。

例如对于 onsubmit 事件:

function validateForm() {
  var x = document.forms["myForm"]["fname"].value;
  if (x == "jaghdjagqfsg") {
    alert("Please answer the question");
    return false;
  }
}

标签: javascriptformsvalidation

解决方案


这是我的想法:我们了解英语中字母的典型频率。然后我们将这些频率与输入文本的频率进行比较。(这可以通过计算“向量差”的大小来完成)。如果频率偏离超过某个阈值,我们将假设输入文本不是可理解的英语。我正在使用一些复制粘贴的诗来了解正常的字母频率——你可以简单地为自己查找一个更明确的频率列表。随着输入更多字符,我使用的阈值变得更严格(过滤掉大部分乱码,允许使用最合理的句子)。右下角的方框表示current score of the entered text/ threshold to beat in order to be considered valid

let textElem = document.querySelector('textarea');
let pElem = document.querySelector('p');

let sampleText = `
Hail to thee, blithe Spirit! Bird thou never wert, That from Heaven, or near it, Pourest thy full heart In profuse strains of unpremeditated art.
Higher still and higher From the earth thou springest Like a cloud of fire; The blue deep thou wingest, And singing still dost soar, and soaring ever singest.
In the golden lightning Of the sunken sun, O'er which clouds are bright'ning, Thou dost float and run; Like an unbodied joy whose race is just begun.
The pale purple even Melts around thy flight; Like a star of Heaven, In the broad day-light Thou art unseen, but yet I hear thy shrill delight,
Keen as are the arrows Of that silver sphere, Whose intense lamp narrows In the white dawn clear Until we hardly see, we feel that it is there.
All the earth and air With thy voice is loud, As, when night is bare, From one lonely cloud The moon rains out her beams, and Heaven is overflow'd.
What thou art we know not; What is most like thee? From rainbow clouds there flow not Drops so bright to see As from thy presence showers a rain of melody.
Like a Poet hidden In the light of thought, Singing hymns unbidden, Till the world is wrought To sympathy with hopes and fears it heeded not:
Like a high-born maiden In a palace-tower, Soothing her love-laden Soul in secret hour With music sweet as love, which overflows her bower:
Like a glow-worm golden In a dell of dew, Scattering unbeholden Its a{:e}real hue Among the flowers and grass, which screen it from the view:
Like a rose embower'd In its own green leaves, By warm winds deflower'd, Till the scent it gives Makes faint with too much sweet those heavy-winged thieves:
Sound of vernal showers On the twinkling grass, Rain-awaken'd flowers, All that ever was Joyous, and clear, and fresh, thy music doth surpass.
Teach us, Sprite or Bird, What sweet thoughts are thine: I have never heard Praise of love or wine That panted forth a flood of rapture so divine.
Chorus Hymeneal, Or triumphal chant, Match'd with thine would be all But an empty vaunt, A thing wherein we feel there is some hidden want.
What objects are the fountains Of thy happy strain? What fields, or waves, or mountains? What shapes of sky or plain? What love of thine own kind? what ignorance of pain?
With thy clear keen joyance Languor cannot be: Shadow of annoyance Never came near thee: Thou lovest: but ne'er knew love's sad satiety.
Waking or asleep, Thou of death must deem Things more true and deep Than we mortals dream, Or how could thy notes flow in such a crystal stream?
We look before and after, And pine for what is not: Our sincerest laughter With some pain is fraught; Our sweetest songs are those that tell of saddest thought.
Yet if we could scorn Hate, and pride, and fear; If we were things born Not to shed a tear, I know not how thy joy we ever should come near.
Better than all measures Of delightful sound, Better than all treasures That in books are found, Thy skill to poet were, thou scorner of the ground!
Teach me half the gladness That thy brain must know, Such harmonious madness From my lips would flow The world should listen then, as I am listening now.
`;

let getCharFrequency = text => {
  
  // Each character increments the value in `f` under the key which is the character
  let f = {};
  for (let char of text.toLowerCase()) f[char] = (f.hasOwnProperty(char) ? f[char] : 0) + 1;
  
  // Normalize this vector by dividing every value by the length
  // Note that `vectorDiffMag` calculates the length if the second
  // vector is `{}` (the "0-vector")
  let len = vectorDiffMag(f, {});
  for (let k in f) f[k] = f[k] / len;
  
  return f;
  
};
let vectorDiffMag = (freq1, freq2) => {
  
  // Returns the magnitude of the vector difference
  // It is essentially a square root of squared differences
  
  let allKeys = new Set([ ...Object.keys(freq1), ...Object.keys(freq2) ]);
  let squareSum = 0;
  for (let key of allKeys) {
    let v1 = freq1.hasOwnProperty(key) ? freq1[key] : 0;
    let v2 = freq2.hasOwnProperty(key) ? freq2[key] : 0;
    let diff = v2 - v1;
    squareSum += diff * diff; // Add the square
  }
  return Math.sqrt(squareSum); // Return the overall square root
  
};

// We only need to compute our "main" frequencies once
let mainFreqs = getCharFrequency(sampleText);

textElem.addEventListener('input', evt => {
  
  // The more characters typed, the stricter the threshold becomes
  // Note these constants allow tuning how strict the threshold
  // becomes as more input is received. I think I've tuned them
  // somewhat well but you may be able to optimize them further:
  let a = 5;     // Control the rate of exponential tightening
  let b = 0.85;  // Control the rate of linear tightening
  let c = 0.55;  // Asymptote (strictest possible threshold)
  let thresh = Math.log(1 + a / textElem.value.length) * b + c;
  
  // Get the magnitude of the vector difference between the "main"
  // frequencies, and the user's input's frequencies
  let diff = vectorDiffMag(mainFreqs, getCharFrequency(textElem.value));
  
  // Render results:
  pElem.innerHTML = `${diff.toFixed(3)} (${thresh.toFixed(2)})`;
  if (diff < thresh) {
    textElem.classList.remove('invalid');
    textElem.classList.add('valid');
  } else {
    textElem.classList.remove('valid');
    textElem.classList.add('invalid');
  }
  
});
textarea {
  position: absolute;
  box-sizing: border-box;
  width: 90%; height: 90%;
  left: 5%; top: 5%;
  resize: none;
  font-size: 150%;
}
textarea.valid { background-color: rgba(0, 150, 0, 0.15); }
textarea.invalid { background-color: rgba(150, 0, 0, 0.15); }
p {
  position: absolute;
  right: 0; bottom: 0;
  padding: 5px; margin: 0;
  background-color: #ffffff;
  box-shadow: inset 0 0 0 1px #000;
  font-size: 120%;
} 
<textarea placeholder="type something!"></textarea>
<p>1.000 / Infinite</p>

编辑:正如 jezpez 所指出的,这几乎不是灵丹妙药!为了获得更好的验证,您需要将此方法与其他技术结合使用。


推荐阅读