javascript - 如何检查输入字段是否包含有效文本而不是表单中的随机字符?
问题描述
我想验证订阅者是否在表单中输入了有意义的英文文本,而不是随机字符,例如“jaghdjagqfsg”。
对于“废话”,我只是指随机字符、仅点/数字/空格、四个或更多辅音等。我只是在寻找不重新发明轮子的食谱或正则表达式模式。
例如对于 onsubmit 事件:
function validateForm() {
var x = document.forms["myForm"]["fname"].value;
if (x == "jaghdjagqfsg") {
alert("Please answer the question");
return false;
}
}
解决方案
这是我的想法:我们了解英语中字母的典型频率。然后我们将这些频率与输入文本的频率进行比较。(这可以通过计算“向量差”的大小来完成)。如果频率偏离超过某个阈值,我们将假设输入文本不是可理解的英语。我正在使用一些复制粘贴的诗来了解正常的字母频率——你可以简单地为自己查找一个更明确的频率列表。随着输入更多字符,我使用的阈值变得更严格(过滤掉大部分乱码,允许使用最合理的句子)。右下角的方框表示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 所指出的,这几乎不是灵丹妙药!为了获得更好的验证,您需要将此方法与其他技术结合使用。
推荐阅读
- angular - 为什么角度元素会出现吞咽错误?
- java - 在 Java 流中执行归约操作时出现异常
- sql - 将表中的列更新为 2 个不同的值
- javascript - 根据下拉值显示 div
- django - 如何将条带支付与现有的 django 表单集成,并且仅在支付成功时保存表单
- angular - 自定义电子邮件指令 Angular 7
- windows - 在 zeit/pkg npm 中找不到包含的 .ps1 文件以运行 node-powershell 命令
- javascript - Electron.js 错误:未定义要求
- c# - 在没有 DBSet 的情况下使用 c#linq 执行 SQL Server 存储过程
- javascript - 带有方形单元格的 HTML 表格适合屏幕高度