在自动校正时更好地跟踪文本字段中的光标位置?

时间:2012-09-30 15:22:10

标签: javascript performance algorithm optimization autocorrect

我正在开发一个jQuery插件,用于实时(自动更正)将拉丁字符转换为日语假名符号(live example),如果我打字速度太快,它可以正常工作..这是一个问题。

例如:

  

wakarimasu - >わかります

然而,当我以正常速度输入时,我得到了这个:

  

wakarimasu - >わかりあすm(实际上是wakariasum,最后是“す”和“m”之间的光标)

如果我输入时没有“su”,我就明白了:

  

wakarima - >わかりあm(实际上是wakariam,最后在“あ”和“m”之间的光标)

我弄清楚了为什么以及如何发生这种情况。基本上,“ri - り”符号仍然是从拉丁语转换为日语假名,而我已经键入“m”并且它在我设置输入“a”之前完成了一点点。因为我的函数在每次转换后定位光标,它将光标定位在“ri”和“m”之间,这就是我的“a”结束的地方。

这也适用于其他词语,但我以此为例。

有没有办法可以更智能地跟踪光标位置,或者是否有办法更新/转换/替换部分文本字段而不更新整个文本字段(现在它的工作方式是它取出了textfield,在函数内部的变量中用kana替换Latin,用变量中的新字符串更新文本字段,然后定位光标)?告诉访客不要太快打字也不是真正的方式..

  

图例:wa =わka =かri =りma =まsu =すa =あ

可以在我提供的链接上查看来源。感谢。

编辑:要考虑的另一件事是用户可能会左右移动光标来添加或删除字符/符号。这使得定位变得复杂,但目前可以正常工作。

2 个答案:

答案 0 :(得分:1)

function translateWord( textarea, oldText, newText ) {
  var ctpos   = getCaretPosition( textarea );

  var textStr = textarea.value;

  var oldTextLen  = oldText.split("").length;
  var newTextLen  = newText.split("").length;

  var txtDiffLen  = ( newTextLen - oldTextLen );

  var escText = oldText.replace( /([()\[\]\\\/+*?.-])/g, "\\$1" );
  var regExpr = new RegExp( "\\b"+escText+"\\b", 'gi' );
  var diffStr = textStr.match( regExpr );
      diffStr = ( diffStr ) ? diffStr.length : 1;

  var newStr  = textStr.replace( regExpr, newText );
      ctpos   = ( ctpos + ( txtDiffLen * diffStr ) );

  textarea.value = newStr;
  setCaretPosition( textarea, ctpos );
}

function getCaretPosition( textarea ) {
  if ( textarea.selectionStart ) {
    return textarea.selectionStart;
  }
  else if ( !document.selection ) {
    return 0;
  }

  var c   = "\001",
      sel = document.selection.createRange(),
      dul = sel.duplicate(),
      len = 0;

  dul.moveToElementText( textarea );
  sel.text  = c;
  len = dul.text.indexOf( c );
  sel.moveStart( 'character', -1 );
  sel.text  = "";
  return len;
}

function setCaretPosition( textarea, pos ) {
  if ( textarea.setSelectionRange ) {
    textarea.focus();
    textarea.setSelectionRange( pos, pos );
  }
  else if ( textarea.createTextRange ) {
    var range = textarea.createTextRange();
        range.collapse( true );
        range.moveEnd( 'character', pos );
        range.moveStart( 'character', pos );
        range.select();
  }
}

translateWord( document.getElementById('text-input'), 'wakarimasu', 'わかります' );

我知道这是一个老问题,但这段代码会帮助像我这样的一些新手:) 来自其他答案的混合函数:)

答案 1 :(得分:0)

为了关闭这个,我设法弄清楚问题实际上是第三个字符(在这种情况下为“m”)进入与“ri”相同的.keyup迭代而不是像我之前想象的那样(症状相同,但原因不同)..

为了解决这个问题,我刚刚修改了.keyup代码,为偏移添加+1,如果在转换后字符串中还留有拉丁语(roumaji)字符,则将光标向右移动一个位置。