使用JavaScript清理从Microsoft Word粘贴的文本

31

我正在使用一个 <div/> 标签,并启用了 PASTE 功能。

从 Microsoft Word 的剪贴板复制粘贴时,会发现大量的标记代码被粘贴进来。我在努力解决这个问题,在使用 Prototypes 的 stripTags() 函数时已经实现了一半(不幸的是,这个函数似乎无法保留某些标签)。

然而,即使如此,我仍然有大量不需要的标记代码。

因此,我的问题是,是否有一些可以清除大部分不必要标记代码的函数(使用 JavaScript)或方法?


祝你好运!从Word中生成的内容(包括粘贴和保存为HTML)确实有待改进啊;-) - scunliffe
我曾经在https://dev59.com/W0bRa4cB1Zd3GeqPwxT_上问过类似的问题,但是你的标题更好。不过,为什么要限制自己只使用JavaScript而不考虑在服务器上完成呢? - Adriano Varoli Piazza
10个回答

24

这是我编写的函数,据我所知,它可以很好地完成任务。

如果有任何改进建议,欢迎提出。谢谢。

function cleanWordPaste( in_word_text ) {
 var tmp = document.createElement("DIV");
 tmp.innerHTML = in_word_text;
 var newString = tmp.textContent||tmp.innerText;
 // this next piece converts line breaks into break tags
 // and removes the seemingly endless crap code
 newString  = newString.replace(/\n\n/g, "<br />").replace(/.*<!--.*-->/g,"");
 // this next piece removes any break tags (up to 10) at beginning
 for ( i=0; i<10; i++ ) {
  if ( newString.substr(0,6)=="<br />" ) { 
   newString = newString.replace("<br />", ""); 
  }
 }
 return newString;
}

希望这对你中的一些人有所帮助。


3

我正在使用这个:

$(body_doc).find('body').bind('paste',function(e){
                var rte = $(this);
                _activeRTEData = $(rte).html();
                beginLen = $.trim($(rte).html()).length; 

                setTimeout(function(){
                    var text = $(rte).html();
                    var newLen = $.trim(text).length;

                    //identify the first char that changed to determine caret location
                    caret = 0;

                    for(i=0;i < newLen; i++){
                        if(_activeRTEData[i] != text[i]){
                            caret = i-1;
                            break;  
                        }
                    }

                    var origText = text.slice(0,caret);
                    var newText = text.slice(caret, newLen - beginLen + caret + 4);
                    var tailText = text.slice(newLen - beginLen + caret + 4, newLen);

                    var newText = newText.replace(/(.*(?:endif-->))|([ ]?<[^>]*>[ ]?)|(&nbsp;)|([^}]*})/g,'');

                    newText = newText.replace(/[·]/g,'');

                    $(rte).html(origText + newText + tailText);
                    $(rte).contents().last().focus();
                },100);
            });
是可编辑的iframe,如果您使用可编辑的div,则可以省略.find('body')部分。基本上它检测到粘贴事件,检查位置,清理新文本,然后将清理后的文本放回粘贴的位置。(听起来有点混乱...但实际上并不像听起来那么糟糕。
setTimeout是必需的,因为只有在文本实际粘贴到元素中时,才能抓取文本,粘贴事件会在粘贴开始时触发。

3

有任何想法函数确切所在的位置(哪个文件)? - OneNerd
2
从*..\fckeditor\editor_source\commandclasses\fckpastewordcommand.js*开始向后走。 - Todd Main

2

如果有一个“粘贴为纯文本”按钮,它会显示一个<textarea>,允许用户将文本粘贴到其中,这样,所有标签都将被剥离。这就是我在我的CMS中所做的;我放弃了尝试清理Word的混乱。


这可能是我的最坏情况(而且看起来可能是唯一的情况 - 非常令人沮丧)。 - OneNerd
@OneNerd:我把你的问题标记为收藏,因为如果其他人有更好的解决方案,我想我也会使用它! - Josh
我想到了一些可能有用的东西 - 如果您愿意,请查看我的答案(并改进它)。谢谢 - - OneNerd
这不就像把小狗的鼻子塞进它在地毯上弄脏的地方吗? - cmc

1
你可以用正则表达式来做这件事。
  1. Remove head tag

  2. Remove script tags

  3. Remove styles tag

    let clipboardData = event.clipboardData || window.clipboardData;
    let pastedText = clipboardData.getData('text/html');
    pastedText = pastedText.replace(/\<head[^>]*\>([^]*)\<\/head/g, '');
    pastedText = pastedText.replace(/\<script[^>]*\>([^]*)\<\/script/g, '');
    pastedText = pastedText.replace(/\<style[^>]*\>([^]*)\<\/style/g, '');
    // pastedText = pastedText.replace(/<(?!(\/\s*)?(b|i|u)[>,\s])([^>])*>/g, '');
    

这是一个示例:https://stackblitz.com/edit/angular-u9vprc


0
我很久以前做过类似的事情,完全清理了富文本编辑器中的内容,并将字体标签转换为样式,br 转换为 p 等,以保持浏览器之间的一致性并防止某些丑陋的东西通过复制粘贴进入。我拿出了递归函数中的大部分内容,只留下核心逻辑,这可能是一个不错的起点(“result”是一个累积结果的对象,可能需要第二次传递转换为字符串),如果这正是你所需的:
var cleanDom = function(result, n) {
var nn = n.nodeName;
if(nn=="#text") {
    var text = n.nodeValue;

    }
else {
    if(nn=="A" && n.href)
        ...;
    else if(nn=="IMG" & n.src) {
        ....
        }
    else if(nn=="DIV") {
        if(n.className=="indent")
            ...
        }
    else if(nn=="FONT") {
        }       
    else if(nn=="BR") {
        }

    if(!UNSUPPORTED_ELEMENTS[nn]) {
        if(n.childNodes.length > 0)
            for(var i=0; i<n.childNodes.length; i++) 
                cleanDom(result, n.childNodes[i]);
        }
    }
}

0

这个方法非常适用于从HTML文本中删除任何注释,包括来自Word的注释:

function CleanWordPastedHTML(sTextHTML) {
  var sStartComment = "<!--", sEndComment = "-->";
  while (true) {
    var iStart = sTextHTML.indexOf(sStartComment);
    if (iStart == -1) break;
    var iEnd = sTextHTML.indexOf(sEndComment, iStart);
    if (iEnd == -1) break;
    sTextHTML = sTextHTML.substring(0, iStart) + sTextHTML.substring(iEnd + sEndComment.length);
  }
  return sTextHTML;
}

0

我曾经遇到过类似的问题,换行符被计算为字符,我不得不将它们删除。

$(document).ready(function(){

  $(".section-overview textarea").bind({
    paste : function(){
    setTimeout(function(){
      //textarea
      var text = $(".section-overview textarea").val();
      // look for any "\n" occurences and replace them
      var newString = text.replace(/\n/g, '');
      // print new string
      $(".section-overview textarea").val(newString);
    },100);
    }
  });
  
});


-1
你能否将内容复制到一个隐藏的文本区域,再从同一文本区域中复制,最后粘贴到你的目标位置?

嗯,你知道一种将粘贴的内容发送到文本区域的方法,以便它确实是纯文本而不是标记代码吗?由于按键事件在 DIV 上,我可以读取内容并将其传递给文本区域,但它不会是纯文本。 - OneNerd
我认为仅将内容保留为文本并不是最佳解决方案。格式很重要。我在一个应用程序中工作,我的客户不希望从Word中删除样式。 - Raul Luna

-4
不得不说,我最终放弃了让TinyMCE按照我的意愿处理Word文档的想法。现在每当用户输入包含某些HTML(例如搜索<span lang="en-US">)时,我就会收到一封电子邮件,并手动进行更正。

3
哎呀,这对我来说不是一个真正的选择。 - OneNerd
2
这是一个非常好的想法,直到您的应用程序拥有超过0个用户。 - Jeff Ryan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接