Javascript 屈服拼写检查器
标题可能有点误导;我的拼写检查器更多地关注格式而不是拼写(大写、标点符号和空格、撇号、将网络俚语转换为完整单词、经常混淆的单词等)。但是,基本原则适用 基本上,我正在构建的JS/jQuery检查器会在键入单词时(在单词后面键入空格或标点符号后)进行更正 然而,就像任何自动更正一样,它肯定会出错。我甚至没有考虑创建功能来确定“its”或“it's”在给定的情况下是否更合适(尽管如果存在这样的插件或代码片段,请给我指出一个) 所以我想让它成为一个“屈服”的自动更正(因为缺乏更好的名字的知识)。基本上Javascript 屈服拼写检查器,javascript,jquery,autocorrect,Javascript,Jquery,Autocorrect,标题可能有点误导;我的拼写检查器更多地关注格式而不是拼写(大写、标点符号和空格、撇号、将网络俚语转换为完整单词、经常混淆的单词等)。但是,基本原则适用 基本上,我正在构建的JS/jQuery检查器会在键入单词时(在单词后面键入空格或标点符号后)进行更正 然而,就像任何自动更正一样,它肯定会出错。我甚至没有考虑创建功能来确定“its”或“it's”在给定的情况下是否更合适(尽管如果存在这样的插件或代码片段,请给我指出一个) 所以我想让它成为一个“屈服”的自动更正(因为缺乏更好的名字的知识)。基本上
我认为这可能是不必要的复杂,或者至少不是一条阻力最小的道路。最聪明的方法是什么?假设您只提交插入符号左边的单词,是否可以禁用拼写检查器,直到键入空白字符或移动文本框插入符号 我不确定这是否是您想要的答案。您建议的方法(在
span
中分隔每个单词并在其中存储额外数据)乍一看似乎是最明智的方法。在编辑器级别,您只需确保所有文本都在某个span
中,并且每个文本只包含一个单词(如有必要,将其拆分)。在单词级,只需聆听span
s(绑定input
和propertyChange
)中的更改,并根据其类别/数据进行操作
然而,真正的痛苦是保持插入符号位置的一致性。当您更改文本区域
或具有内容可编辑
的元素的内容时,插入符号的移动相当不可预测,并且没有简单的(跨浏览器)方法跟踪插入符号。我在SO和其他地方寻找解决方案,我找到的最简单的工作解决方案是。不幸的是,它只适用于textarea
,因此“一个span中的每个单词”解决方案无法使用
因此,我建议采取以下方法:
- 在
数组中保留一个单词列表,每个单词都存储当前值和原始值李>
- 当
的内容发生变化时,保留一组不变的单词,然后重做其余的单词李>textarea
- 只有在插入符号刚好位于非单词字符之后(有待改进),并且您没有点击
退格时,才应用拼写检查李>
- 如果用户对更正不满意,单击一次
将撤消更正,并且除非修改,否则不会再次检查更正。退格
- 如果一次做了许多更正(例如,如果复制粘贴了大量文本),则每个
将撤消一个更正,直到没有人留下退格
- 点击任何其他键都将提交更正,因此如果用户仍然不满意,他将不得不返回并再次更改
- 注:与OP要求不同,如果用户输入非单词字符,则更改的版本将再次自动更正;他需要点击
退格一次来“保护”它
- 当
详细说明了测试步骤:
- 在
数组中保留一个单词列表,每个单词都存储当前值和原始值
此正则表达式将文本拆分为多个单词(每个单词都有一个var words = [];
属性和一个word
属性;后者紧跟其后存储非单词字符)sp
- 当
的内容发生变化时,保留一组不变的单词,然后重做其余的单词textarea
// Split all the text var split = $.autocorrect.regexSplit(options.delimiter, $this.val()); // Find unchanged words in the beginning of the field var start = 0; while ( start < words.length && start < split.length ) { if ( !words[start].equals(split[start]) ) break; start++; } // Find unchanged words in the end of the field var end = 0; while ( 0 < words.length - end && 0 < split.length - end ) { if ( !words[words.length-end-1].equals(split[split.length-end-1]) || words.length-end-1 < start ) break; end++; } // Autocorrects words in-between var toSplice = [start, words.length-end - start]; for ( var i = start ; i < split.length-end ; i++ ) toSplice.push({ word:check(split[i], i), sp:split[i].sp, original:split[i].word, equals:function(w) { return this.word == w.word && this.sp == w.sp; } }); words.splice.apply(words, toSplice); // Updates the text, preserving the caret position updateText();
- 如果用户对更正不满意,单击一次
将撤消更正,并且除非修改,否则不会再次检查更正退格
$(this).keydown(function(e) { if ( e.which == 8 ) { if ( stack.length > 0 ) { var last = stack.pop(); words[last].word = words[last].original; updateText(last); return false; } else backtracking = true; stack = []; } });
的代码只是将所有单词再次合并成一个字符串,并将值设置回updateText
。如果未更改任何内容,或在上一次自动更正完成/撤消后放置任何内容,则会保留插入符号,以说明文本长度的更改:textarea
function updateText(undone) { var caret = doGetCaretPosition(element); var text = ""; for ( var i = 0 ; i < words.length ; i++ ) text += words[i].word + words[i].sp; $this.val(text); // If a word was autocorrected, put the caret right after it if ( stack.length > 0 || undone !== undefined ) { var last = undone !== undefined ? undone : stack[stack.length-1]; caret = 0; for ( var i = 0 ; i < last ; i++ ) caret += words[i].word.length + words[i].sp.length; caret += words[last].word.length + 1; } setCaretPosition(element,caret); }
$(this).keydown(function(e) {
if ( e.which == 8 ) {
if ( stack.length > 0 ) {
var last = stack.pop();
words[last].word = words[last].original;
updateText(last);
return false;
}
else
backtracking = true;
stack = [];
}
});
function updateText(undone) {
var caret = doGetCaretPosition(element);
var text = "";
for ( var i = 0 ; i < words.length ; i++ )
text += words[i].word + words[i].sp;
$this.val(text);
// If a word was autocorrected, put the caret right after it
if ( stack.length > 0 || undone !== undefined ) {
var last = undone !== undefined ? undone : stack[stack.length-1];
caret = 0;
for ( var i = 0 ; i < last ; i++ )
caret += words[i].word.length + words[i].sp.length;
caret += words[last].word.length + 1;
}
setCaretPosition(element,caret);
}
$.fn.autocorrect = function(options) {
options = $.extend({
delimiter:/^(\w+)(\W+)(.*)$/,
checker:function(x) { return x; }
}, options);
return this.each(function() {
var element = this, $this = $(this);
var words = [];
var stack = [];
var backtracking = false;
function updateText(undone) { ... }
$this.bind("input propertyChange", function() {
stack = [];
// * Only apply the spell check if the caret...
// * When the contents of the `textarea` changes...
backtracking = false;
});
// * If the user was unsatisfied with the correction...
});
};
$.autocorrect = {
regexSplit:function(regex,text) { ... }
};