选择单词边界,但不包括标点符号

Selection to word boundaries, but excluding punctuation signs

本文关键字:不包括 标点符号 单词 边界 选择      更新时间:2023-09-26

我尝试修改用户所做的选择,使其始终是完整的单词。例如,鉴于"报告:奥巴马总统寻求在阿富汗保留9800名美军……"消息人士说,今年之后,如果用户只是选择"阿富汗人",我希望选择修改为"阿富汗"。经过一番搜索,我在Stackoverflow上偶然发现了以下解决方案:

snapSelectionToWord : function() {
  var sel;
  if (window.getSelection && (sel = window.getSelection()).modify) {
    sel = window.getSelection();
    if (!sel.isCollapsed) {
        // Detect if selection is backwards
        var range = document.createRange();
        range.setStart(sel.anchorNode, sel.anchorOffset);
        range.setEnd(sel.focusNode, sel.focusOffset);
        var backwards = range.collapsed;
        range.detach();
        // modify() works on the focus of the selection
        var endNode = sel.focusNode, endOffset = sel.focusOffset;
        sel.collapse(sel.anchorNode, sel.anchorOffset);
        var direction = [];
        if (backwards) {
            direction = ['backward', 'forward'];
        } else {
            direction = ['forward', 'backward'];
        }
        sel.modify("move", direction[0], "character");
        sel.modify("move", direction[1], "word");
        sel.extend(endNode, endOffset);
        sel.modify("extend", direction[1], "character");
        sel.modify("extend", direction[0], "word");
    }
  } else if ( (sel = document.selection) && sel.type != "Control") {
      var textRange = sel.createRange();
      if (textRange.text) {
        textRange.expand("word");
        // Move the end back to not include the word's trailing space(s), if necessary
        while (/'s$/.test(textRange.text)) {
            textRange.moveEnd("character", -1);
        }
        textRange.select();
    }
  }
},

原则上,它工作得很好。然而,也有一些病理病例。例如,选择"阿富汗……"时,它会切换到"阿富汗……"(我想要"阿富汗")。和选择的结果是一样的。(这里期望的结果是:"after")。主要问题似乎是粒度word只考虑空格而不考虑其他标点符号。

我现在的想法是将粒度从word更改为character,并将其放入循环中,直到达到标点符号。这对于sel.modify("extend", ...);行工作得很好,但对于sel.modify("move", ...);行则不是(如预期的那样)。在collapse和第一次move修改之后,sel.toString()都是空的。因此,我不能循环第一个/最后一个字符来逐字符移动。在sel.extend(endNode, endOffset);之后,再次设置sel.toString(),并且使用循环的方法有效。

我偶然发现了rangy,它很好地解决了我的问题。使用这个库将我的函数简化为:

snapSelectionToWord : function() {
  rangy.getSelection().expand("word");
},

感谢开发者让我的生活变得如此轻松!