javascript - VBA JavaScript 对象不支持此属性或方法

标签 javascript vba scriptcontrol

我正在尝试从 https://github.com/cgiffard/TextStatistics.js/blob/master/index.js 获取文本统计功能

在 Excel 中工作

我缩小了 JavaScript 代码以缩短连接

Function Text_Statistics1(textString As String)

Dim code As String

code = "function text_stats(teststringtoprocess){(function(e){function t(e){var t=['li','p','h1','h2','h3','h4','h5','h6','dd'];t.forEach(function(t){e=e.replace('</'+t+'>','.')});e=e.replace(/<[^>]+>/g,'').replace(/[,:;()\-]/,' ').replace(/[\.!?]/,'.').replace(/^\s+/,'').replace(/[ ]*(\n|\r\n|\r)[ ]*/,' ').replace(/([\.])[\. ]+/,'.').replace(/[ ]*([\.])/,'. ').replace(/\s+/,' ').replace(/\s+$/,'');e+='.';return e}function r(e){return new n(e)}var n=function(n){this.text=n?t(n):this.text};n.prototype.fleschKincaidReadingEase=function(e){e=e?t(e):this.text;return Math.round((206.835-1.015*this.averageWordsPerSentence(e)-84.6*this.averageSyllablesPerWord(e))*10)/10};n.prototype.fleschKincaidGradeLevel=function(e){e=e?t(e):this.text;return Math.round((.39*this.averageWordsPerSentence(e)+11.8*this.averageSyllablesPerWord(e)-15.59)*10)/10};n.prototype.gunningFogScore=function(e){e=e?t(e):this.text;"
code = code + "return Math.round((this.averageWordsPerSentence(e)+this.percentageWordsWithThreeSyllables(e,false))*.4*10)/10};n.prototype.colemanLiauIndex=function(e){e=e?t(e):this.text;return Math.round((5.89*(this.letterCount(e)/this.wordCount(e))-.3*(this.sentenceCount(e)/this.wordCount(e))-15.8)*10)/10};n.prototype.smogIndex=function(e){e=e?t(e):this.text;return Math.round(1.043*Math.sqrt(this.wordsWithThreeSyllables(e)*(30/this.sentenceCount(e))+3.1291)*10)/10};n.prototype.automatedReadabilityIndex=function(e){e=e?t(e):this.text;"
code = code + "return Math.round((4.71*(this.letterCount(e)/this.wordCount(e))+.5*(this.wordCount(e)/this.sentenceCount(e))-21.43)*10)/10};n.prototype.textLength=function(e){e=e?t(e):this.text;return e.length};n.prototype.letterCount=function(e){e=e?t(e):this.text;e=e.replace(/[^a-z]+/ig,'');return e.length};n.prototype.sentenceCount=function(e){e=e?t(e):this.text;return e.replace(/[^\.!?]/g,'').length||1};n.prototype.wordCount=function(e){e=e?t(e):this.text;return e.split(/[^a-z0-9]+/i).length||1};n.prototype.averageWordsPerSentence=function(e){e=e?t(e):this.text;"
code = code + "return this.wordCount(e)/this.sentenceCount(e)};n.prototype.averageSyllablesPerWord=function(e){e=e?t(e):this.text;var n=0,r=this.wordCount(e),i=this;e.split(/\s+/).forEach(function(e){n+=i.syllableCount(e)});return(n||1)/(r||1)};n.prototype.wordsWithThreeSyllables=function(e,n){e=e?t(e):this.text;var r=0,i=this;n=n===false?false:true;e.split(/\s+/).forEach(function(e){if(!e.match(/^[A-Z]/)||n){if(i.syllableCount(e)>2)r++}});return r};n.prototype.percentageWordsWithThreeSyllables=function(e,n){e=e?t(e):this.text;return this.wordsWithThreeSyllables(e,n)/this.wordCount(e)*100};n.prototype.syllableCount=function(e){var t=0,n=0,r=0;e=e.toLowerCase().replace(/[^a-z]/g,'');var i={simile:3,forever:3,shoreline:2};if(i.hasOwnProperty(e))return i[e];var s=[/cial/,/tia/,/cius/,/cious/,/giu/,/ion/,/iou/,/sia$/,/[^aeiuoyt]{2,}ed$/,/.ely$/,/[cg]h?e[rsd]?$/,/rved?$/,/[aeiouy][dt]es?$/,/[aeiouy][^aeiouydt]e[rsd]?$/,/^[dr]e[aeiou][^aeiou]+$/,/[aeiouy]rse$/];"
code = code + "var o=[/ia/,/riet/,/dien/,/iu/,/io/,/ii/,/[aeiouym]bl$/,/[aeiou]{3}/,/^mc/,/ism$/,/([^aeiouy])\1l$/,/[^l]lien/,/^coa[dglx]./,/[^gq]ua[^auieo]/,/dnt$/,/uity$/,/ie(r|st)$/];var u=[/^un/,/^fore/,/ly$/,/less$/,/ful$/,/ers?$/,/ings?$/];u.forEach(function(t){if(e.match(t)){e=e.replace(t,'');n++}});r=e.split(/[^aeiouy]+/ig).filter(function(e){return!!e.replace(/\s+/ig,'').length}).length;t=r+n;s.forEach(function(n){if(e.match(n))t--});o.forEach(function(n){if(e.match(n))t++});return t||1};typeof module!='undefined'&&module.exports?module.exports=r:typeof define!='undefined'?define('textstatistics',[],function(){return r}):e.textstatistics=r})(this);"

'code = code + " return textstatistics(s).fleschKincaidReadingEase();" & _
'"return stat.fleschKincaidReadingEase();" & _

code = code + "return textstatistics(teststringtoprocess).fleschKincaidReadingEase();}"
'code = code + "return textstatistics(teststringtoprocess);}"



Dim o As New ScriptControl
    o.Language = "JScript"
    With o
        .AddCode code
        Text_Statistics1 = .Run("text_stats", textString)
    End With

End Function

我收到的对象不支持此属性或方法 - 我认为这是由于文本统计信息的实例化造成的。

我是否需要将 javascript 转换为一组函数?

更新: 使用 eval 的方法略有不同

Function Text_Stat(textString As String, textstat As String)

Dim code As String

code = "(function(e){function t(e){var t=['li','p','h1','h2','h3','h4','h5','h6','dd'];t.forEach(function(t){e=e.replace('</'+t+'>','.')});e=e.replace(/<[^>]+>/g,'').replace(/[,:;()\-]/,' ').replace(/[\.!?]/,'.').replace(/^\s+/,'').replace(/[ ]*(\n|\r\n|\r)[ ]*/,' ').replace(/([\.])[\. ]+/,'.').replace(/[ ]*([\.])/,'. ').replace(/\s+/,' ').replace(/\s+$/,'');e+='.';return e}function r(e){return new n(e)}var n=function(n){this.text=n?t(n):this.text};n.prototype.fleschKincaidReadingEase=function(e){e=e?t(e):this.text;return Math.round((206.835-1.015*this.averageWordsPerSentence(e)-84.6*this.averageSyllablesPerWord(e))*10)/10};n.prototype.fleschKincaidGradeLevel=function(e){e=e?t(e):this.text;" & _
"return Math.round((.39*this.averageWordsPerSentence(e)+11.8*this.averageSyllablesPerWord(e)-15.59)*10)/10};n.prototype.gunningFogScore=function(e){e=e?t(e):this.text;return Math.round((this.averageWordsPerSentence(e)+this.percentageWordsWithThreeSyllables(e,false))*.4*10)/10};n.prototype.colemanLiauIndex=function(e){e=e?t(e):this.text;return Math.round((5.89*(this.letterCount(e)/this.wordCount(e))-.3*(this.sentenceCount(e)/this.wordCount(e))-15.8)*10)/10};n.prototype.smogIndex=function(e){e=e?t(e):this.text;return Math.round(1.043*Math.sqrt(this.wordsWithThreeSyllables(e)*(30/this.sentenceCount(e))+3.1291)*10)/10};n.prototype.automatedReadabilityIndex=function(e){e=e?t(e):this.text;" & _
"return Math.round((4.71*(this.letterCount(e)/this.wordCount(e))+.5*(this.wordCount(e)/this.sentenceCount(e))-21.43)*10)/10};n.prototype.textLength=function(e){e=e?t(e):this.text;return e.length};n.prototype.letterCount=function(e){e=e?t(e):this.text;e=e.replace(/[^a-z]+/ig,'');return e.length};n.prototype.sentenceCount=function(e){e=e?t(e):this.text;return e.replace(/[^\.!?]/g,'').length||1};n.prototype.wordCount=function(e){e=e?t(e):this.text;return e.split(/[^a-z0-9]+/i).length||1};n.prototype.averageWordsPerSentence=function(e){e=e?t(e):this.text;return this.wordCount(e)/this.sentenceCount(e)};n.prototype.averageSyllablesPerWord=function(e){e=e?t(e):this.text;var n=0,r=this.wordCount(e),i=this;e.split(/\s+/).forEach(function(e){n+=i.syllableCount(e)});return(n||1)/(r||1)};n.prototype.wordsWithThreeSyllables=function(e,n){e=e?t(e):this.text;" & _
"var r=0,i=this;n=n===false?false:true;e.split(/\s+/).forEach(function(e){if(!e.match(/^[A-Z]/)||n){if(i.syllableCount(e)>2)r++}});return r};n.prototype.percentageWordsWithThreeSyllables=function(e,n){e=e?t(e):this.text;" & _
"return this.wordsWithThreeSyllables(e,n)/this.wordCount(e)*100};n.prototype.syllableCount=function(e){var t=0,n=0,r=0;e=e.toLowerCase().replace(/[^a-z]/g,'');var i={simile:3,forever:3,shoreline:2};if(i.hasOwnProperty(e))return i[e];var s=[/cial/,/tia/,/cius/,/cious/,/giu/,/ion/,/iou/,/sia$/,/[^aeiuoyt]{2,}ed$/,/.ely$/,/[cg]h?e[rsd]?$/,/rved?$/,/[aeiouy][dt]es?$/,/[aeiouy][^aeiouydt]e[rsd]?$/,/^[dr]e[aeiou][^aeiou]+$/,/[aeiouy]rse$/];var o=[/ia/,/riet/,/dien/,/iu/,/io/,/ii/,/[aeiouym]bl$/,/[aeiou]{3}/,/^mc/,/ism$/,/([^aeiouy])\1l$/,/[^l]lien/,/^coa[dglx]./,/[^gq]ua[^auieo]/,/dnt$/,/uity$/,/ie(r|st)$/];" & _
"var u=[/^un/,/^fore/,/ly$/,/less$/,/ful$/,/ers?$/,/ings?$/];u.forEach(function(t){if(e.match(t)){e=e.replace(t,'');n++}});r=e.split(/[^aeiouy]+/ig).filter(function(e){return!!e.replace(/\s+/ig,'').length}).length;t=r+n;s.forEach(function(n){if(e.match(n))t--});o.forEach(function(n){if(e.match(n))t++});return t||1};typeof module!='undefined'&&module.exports?module.exports=r:typeof define!='undefined'?define('textstatistics',[],function(){return r}):e.textstatistics=r})(this);" & _
"var stat = new textstatistics('Your text here');alert(stat.sentenceCount('This. dfgdfg. is. a. long. sentence.'));"


Dim o As New ScriptControl
    o.Language = "JScript"
    With o
        .AllowUI = True
        .AddCode code
        .Eval "stat.sentenceCount('This. dfgdfg. is. a. long. sentence.')"
        'result = .Eval(code)
        'Debug.Print .Eval("'Hello World'.substring(1, 4);")
        'result = .Eval(result)
        'Text_Stat = .Run(result)
    End With

End Function

JSFiddle 显示它在这里工作 http://jsfiddle.net/hwr26dkf/

更新:2014 年 1 月 10 日 感谢 Michael Petch 的最终工作 VBA 版本

Function Text_Statistics(statType As Integer, textString As String)

Dim wc, sc As Integer
Dim s1, s2, code As String
Dim oTextStats As Object
Dim o As New ScriptControl

code = "function cleanText(e){var t=['li','p','h1','h2','h3','h4','h5','h6','dd'];t.forEach(function(t){e=e.replace('</'+t+'>','.')});e=e.replace(/<[^>]+>/g,'').replace(/[,:;()\-]/,' ').replace(/[\.!?]/,'.').replace(/^\s+/,'').replace(/[ ]*(\n|\r\n|\r)[ ]*/,' ').replace(/([\.])[\. ]+/,'.').replace(/[ ]*([\.])/,'. ').replace(/\s+/,' ').replace(/\s+$/,'');e+='.';return e}function textStatistics(e){return new TextStatistics(e)}if(!Array.prototype.forEach){Array.prototype.forEach=function(e){var t=this.length;" & _
"if(typeof e!='function')throw new TypeError;var n=arguments[1];for(var r=0;r<t;r++){if(r in this)e.call(n,this[r],r,this)}}}if(!Array.prototype.filter){Array.prototype.filter=function(e){'use strict';if(this===void 0||this===null){throw new TypeError}var t=Object(this);var n=t.length>>>0;if(typeof e!=='function'){throw new TypeError}var r=[];var i=arguments.length>=2?arguments[1]:void 0;for(var s=0;s<n;s++){if(s in t){var o=t[s];if(e.call(i,o,s,t)){r.push(o)}}}return r}}var TextStatistics=function(t){this.text=t?cleanText(t):this.text};TextStatistics.prototype.fleschKincaidReadingEase=function(e){e=e?cleanText(e):this.text;return Math.round((206.835-1.015*this.averageWordsPerSentence(e)-84.6*this.averageSyllablesPerWord(e))*10)/10};TextStatistics.prototype.fleschKincaidGradeLevel=function(e){e=e?cleanText(e):this.text;" & _
"return Math.round((.39*this.averageWordsPerSentence(e)+11.8*this.averageSyllablesPerWord(e)-15.59)*10)/10};TextStatistics.prototype.gunningFogScore=function(e){e=e?cleanText(e):this.text;return Math.round((this.averageWordsPerSentence(e)+this.percentageWordsWithThreeSyllables(e,false))*.4*10)/10};TextStatistics.prototype.colemanLiauIndex=function(e){e=e?cleanText(e):this.text;return Math.round((5.89*(this.letterCount(e)/this.wordCount(e))-.3*(this.sentenceCount(e)/this.wordCount(e))-15.8)*10)/10};" & _
"TextStatistics.prototype.smogIndex=function(e){e=e?cleanText(e):this.text;return Math.round(1.043*Math.sqrt(this.wordsWithThreeSyllables(e)*(30/this.sentenceCount(e))+3.1291)*10)/10};TextStatistics.prototype.automatedReadabilityIndex=function(e){e=e?cleanText(e):this.text;return Math.round((4.71*(this.letterCount(e)/this.wordCount(e))+.5*(this.wordCount(e)/this.sentenceCount(e))-21.43)*10)/10};TextStatistics.prototype.textLength=function(e){e=e?cleanText(e):this.text;return e.length};TextStatistics.prototype.letterCount=function(e){e=e?cleanText(e):this.text;e=e.replace(/[^a-z]+/ig,'');return e.length};TextStatistics.prototype.sentenceCount=function(e){e=e?cleanText(e):this.text;" & _
"return e.replace(/[^\.!?]/g,'').length||1};TextStatistics.prototype.wordCount=function(e){e=e?cleanText(e):this.text;return e.split(/[^a-z0-9]+/i).length||1};TextStatistics.prototype.averageWordsPerSentence=function(e){e=e?cleanText(e):this.text;return this.wordCount(e)/this.sentenceCount(e)};TextStatistics.prototype.averageSyllablesPerWord=function(e){e=e?cleanText(e):this.text;" & _
"var t=0,n=this.wordCount(e),r=this;e.split(/\s+/).forEach(function(e){t+=r.syllableCount(e)});return(t||1)/(n||1)};TextStatistics.prototype.wordsWithThreeSyllables=function(e,t){e=e?cleanText(e):this.text;var n=0,r=this;t=t===false?false:true;e.split(/\s+/).forEach(function(e){if(!e.match(/^[A-Z]/)||t){if(r.syllableCount(e)>2)n++}});return n};TextStatistics.prototype.percentageWordsWithThreeSyllables=function(e,t){e=e?cleanText(e):this.text;return this.wordsWithThreeSyllables(e,t)/this.wordCount(e)*100};" & _
"TextStatistics.prototype.syllableCount=function(e){var t=0,n=0,r=0;e=e.toLowerCase().replace(/[^a-z]/g,'');var i={simile:3,forever:3,shoreline:2};if(i.hasOwnProperty(e))return i[e];var s=[/cial/,/tia/,/cius/,/cious/,/giu/,/ion/,/iou/,/sia$/,/[^aeiuoyt]{2,}ed$/,/.ely$/,/[cg]h?e[rsd]?$/,/rved?$/,/[aeiouy][dt]es?$/,/[aeiouy][^aeiouydt]e[rsd]?$/,/^[dr]e[aeiou][^aeiou]+$/,/[aeiouy]rse$/];var o=[/ia/,/riet/,/dien/,/iu/,/io/,/ii/,/[aeiouym]bl$/,/[aeiou]{3}/,/^mc/,/ism$/,/([^aeiouy])\1l$/,/[^l]lien/,/^coa[dglx]./,/[^gq]ua[^auieo]/,/dnt$/,/uity$/,/ie(r|st)$/];" & _
"var u=[/^un/,/^fore/,/ly$/,/less$/,/ful$/,/ers?$/,/ings?$/];u.forEach(function(t){if(e.match(t)){e=e.replace(t,'');n++}});r=e.split(/[^aeiouy]+/ig).filter(function(e){return!!e.replace(/\s+/ig,'').length}).length;t=r+n;s.forEach(function(n){if(e.match(n))t--});o.forEach(function(n){if(e.match(n))t++});return t||1}"

With o
    .Language = "JScript"
    .AddCode code
    ' Create a TextStatistics object initially with no text.
    ' textStatistics is a function that creates TextStatistics objects
    Set oTextStats = .Eval("textStatistics()")

    ' Now simply call TextStatistics methods directly
    wc = oTextStats.averageWordsPerSentence(textString)
    sc = oTextStats.syllableCount(textString)

    ' Alternatively you can create a TextStatistics object with the text
    ' and call the methods with a blank string to return the values
    ' for the string passed in the constructor

    'Set oTextStats = .Eval("textStatistics('" + textString + "')")
    'wc = oTextStats.wordCount("")
    'sc = oTextStats.sentenceCount("")


    Select Case statType
    Case 1
        Text_Statistics = oTextStats.wordCount(textString)
    Case 2
        Text_Statistics = oTextStats.sentenceCount(textString)
    Case 3
        Text_Statistics = oTextStats.fleschKincaidReadingEase(textString)
    Case 4
        Text_Statistics = oTextStats.fleschKincaidGradeLevel(textString)
    Case 5
        Text_Statistics = oTextStats.gunningFogScore(textString)
    Case 6
        Text_Statistics = oTextStats.colemanLiauIndex(textString)
    Case 7
        Text_Statistics = oTextStats.smogIndex(textString)
    Case 8
        Text_Statistics = oTextStats.automatedReadabilityIndex(textString)
    Case 9
        Text_Statistics = oTextStats.textLength(textString)
   Case 10
        Text_Statistics = oTextStats.letterCount(textString)
   Case 11
        Text_Statistics = oTextStats.averageWordsPerSentence(textString)
   Case 12
        Text_Statistics = oTextStats.averageSyllablesPerWord(textString)

End Select

End With
End Function

最佳答案

我今天下午花了一些时间学习 Javascript,然后试图弄清楚当您的 TextStatistics 类在 Microsoft 的 ScriptControl 对象中运行时发生了什么。我没有从 VBA 中损坏的代码开始,而是回到了 github 中的代码。 OP引用的。我发现的第一件事是 ScriptControl 将解析并执行匿名全局函数,但是一旦 ScriptControl 添加了该代码,它似乎就失去了对 TextStatistics 对象的跟踪。所以我做的第一件事就是通过删除顶部的这个来简单地删除匿名全局函数:

(function(glob) {

并删除底部的这些行:

(typeof module != "undefined" && module.exports) ? (module.exports = textStatistics) : (typeof define != "undefined" ? (define("textstatistics", [], function() { return textStatistics; })) : (glob.textstatistics = textStatistics));
})(this);

一旦我将其作为问题根源移除,我发现我可以创建 TextStatistics 的新实例,但我无法正确地为它们分配文本。既不是使用 new 作为参数,也不是通过调用 sentenceCount() 之类的方法。这让我很困惑。由于无法正确创建 TextStatistics 实例,因此我决定检查构造函数。它很简单,但它调用了 cleanText。让我印象深刻的一件事是 forEach。凭直觉我做了一些关于 Javascript/ScriptControl 的挖掘,然后是 forEach。我了解到 ScriptControl 使用 ECMAScript 而不是 Javascript。一旦我弄清楚了,我就找到了这个 information 的链接。其中包括这条评论:关于 forEach 方法:

This method is a JavaScript extension to the ECMA-262 standard; as such it may not be present in other implementations of the standard. To make it work you need to add following code at the top of your script:

还有这段代码:

if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fun /*, thisp*/ ) {
        var len = this.length;
        if (typeof fun != 'function') throw new TypeError();

        var thisp = arguments[1];
        for (var i = 0; i < len; i++) {
            if (i in this) fun.call(thisp, this[i], i, this);
        }
    };
}

在提供我的原始答案后,OP 发现涉及音节的功能不起作用。在后来的 ECMA 规范中出现了另一个 ScriptControl 不支持的函数。那是数组上的 polyfill filter 函数。根据这个Mozilla documentation :

filter was added to the ECMA-262 standard in the 5th edition; as such it may not be present in all implementations of the standard. You can work around this by inserting the following code at the beginning of your scripts, allowing use of filter in ECMA-262 implementations which do not natively support it.

提供的符合规范的代码:

if (!Array.prototype.filter) {
  Array.prototype.filter = function(fun/*, thisArg*/) {
    'use strict';

    if (this === void 0 || this === null) {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var res = [];
    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++) {
      if (i in t) {
        var val = t[i];

        // NOTE: Technically this should Object.defineProperty at
        //       the next index, as push can be affected by
        //       properties on Object.prototype and Array.prototype.
        //       But that method's new, and collisions should be
        //       rare, so use the more-compatible alternative.
        if (fun.call(thisArg, val, i, t)) {
          res.push(val);
        }
      }
    }

    return res;
  };
}

有这么简单吗?这是造成这些问题的原因吗?是的。我将该代码添加到脚本的顶部,并且包含 VBA 和 ScriptControl。因此,在缩小并将所有 " 转换为 ' 之前,整个 Javascript 代码如下所示:

if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fun /*, thisp*/ ) {
        var len = this.length;
        if (typeof fun != 'function') throw new TypeError();

        var thisp = arguments[1];
        for (var i = 0; i < len; i++) {
            if (i in this) fun.call(thisp, this[i], i, this);
        }
    };
}

if (!Array.prototype.filter) {
  Array.prototype.filter = function(fun/*, thisArg*/) {
    'use strict';

    if (this === void 0 || this === null) {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var res = [];
    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++) {
      if (i in t) {
        var val = t[i];

        // NOTE: Technically this should Object.defineProperty at
        //       the next index, as push can be affected by
        //       properties on Object.prototype and Array.prototype.
        //       But that method's new, and collisions should be
        //       rare, so use the more-compatible alternative.
        if (fun.call(thisArg, val, i, t)) {
          res.push(val);
        }
      }
    }

    return res;
  };
}

function cleanText(text) {
    // all these tags should be preceeded by a full stop. 
    var fullStopTags = ['li', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dd'];

    fullStopTags.forEach(function (tag) {
        text = text.replace('</' + tag + '>', '.');
    });

    text = text.replace(/<[^>]+>/g, '') // Strip tags
    .replace(/[,:;()\-]/, ' ') // Replace commans, hyphens etc (count them as spaces)
    .replace(/[\.!?]/, '.') // Unify terminators
    .replace(/^\s+/, '') // Strip leading whitespace
    .replace(/[ ]*(\n|\r\n|\r)[ ]*/, ' ') // Replace new lines with spaces
    .replace(/([\.])[\. ]+/, '.') // Check for duplicated terminators
    .replace(/[ ]*([\.])/, '. ') // Pad sentence terminators
    .replace(/\s+/, ' ') // Remove multiple spaces
    .replace(/\s+$/, ''); // Strip trailing whitespace

    text += '.'; // Add final terminator, just in case it's missing.

    return text;
}

var TextStatistics = function TextStatistics(text) {
    this.text = text ? cleanText(text) : this.text;
};

TextStatistics.prototype.fleschKincaidReadingEase = function (text) {
    text = text ? cleanText(text) : this.text;
    return Math.round((206.835 - (1.015 * this.averageWordsPerSentence(text)) - (84.6 * this.averageSyllablesPerWord(text))) * 10) / 10;
};

TextStatistics.prototype.fleschKincaidGradeLevel = function (text) {
    text = text ? cleanText(text) : this.text;
    return Math.round(((0.39 * this.averageWordsPerSentence(text)) + (11.8 * this.averageSyllablesPerWord(text)) - 15.59) * 10) / 10;
};

TextStatistics.prototype.gunningFogScore = function (text) {
    text = text ? cleanText(text) : this.text;
    return Math.round(((this.averageWordsPerSentence(text) + this.percentageWordsWithThreeSyllables(text, false)) * 0.4) * 10) / 10;
};

TextStatistics.prototype.colemanLiauIndex = function (text) {
    text = text ? cleanText(text) : this.text;
    return Math.round(((5.89 * (this.letterCount(text) / this.wordCount(text))) - (0.3 * (this.sentenceCount(text) / this.wordCount(text))) - 15.8) * 10) / 10;
};

TextStatistics.prototype.smogIndex = function (text) {
    text = text ? cleanText(text) : this.text;
    return Math.round(1.043 * Math.sqrt((this.wordsWithThreeSyllables(text) * (30 / this.sentenceCount(text))) + 3.1291) * 10) / 10;
};

TextStatistics.prototype.automatedReadabilityIndex = function (text) {
    text = text ? cleanText(text) : this.text;
    return Math.round(((4.71 * (this.letterCount(text) / this.wordCount(text))) + (0.5 * (this.wordCount(text) / this.sentenceCount(text))) - 21.43) * 10) / 10;
};

TextStatistics.prototype.textLength = function (text) {
    text = text ? cleanText(text) : this.text;
    return text.length;
};

TextStatistics.prototype.letterCount = function (text) {
    text = text ? cleanText(text) : this.text;
    text = text.replace(/[^a-z]+/ig, '');
    return text.length;
};

TextStatistics.prototype.sentenceCount = function (text) {
    text = text ? cleanText(text) : this.text;

    // Will be tripped up by 'Mr.' or 'U.K.'. Not a major concern at this point.
    return text.replace(/[^\.!?]/g, '').length || 1;
};

TextStatistics.prototype.wordCount = function (text) {
    text = text ? cleanText(text) : this.text;
    return text.split(/[^a-z0-9]+/i).length || 1;
};

TextStatistics.prototype.averageWordsPerSentence = function (text) {
    text = text ? cleanText(text) : this.text;
    return this.wordCount(text) / this.sentenceCount(text);
};

TextStatistics.prototype.averageSyllablesPerWord = function (text) {
    text = text ? cleanText(text) : this.text;
    var syllableCount = 0,
        wordCount = this.wordCount(text),
        self = this;

    text.split(/\s+/).forEach(function (word) {
        syllableCount += self.syllableCount(word);
    });

    // Prevent NaN...
    return (syllableCount || 1) / (wordCount || 1);
};

TextStatistics.prototype.wordsWithThreeSyllables = function (text, countProperNouns) {
    text = text ? cleanText(text) : this.text;
    var longWordCount = 0,
        self = this;

    countProperNouns = countProperNouns === false ? false : true;

    text.split(/\s+/).forEach(function (word) {

        // We don't count proper nouns or capitalised words if the countProperNouns attribute is set.
        // Defaults to true.
        if (!word.match(/^[A-Z]/) || countProperNouns) {
            if (self.syllableCount(word) > 2) longWordCount++;
        }
    });

    return longWordCount;
};

TextStatistics.prototype.percentageWordsWithThreeSyllables = function (text, countProperNouns) {
    text = text ? cleanText(text) : this.text;

    return (this.wordsWithThreeSyllables(text, countProperNouns) / this.wordCount(text)) * 100;
};

TextStatistics.prototype.syllableCount = function (word) {
    var syllableCount = 0,
        prefixSuffixCount = 0,
        wordPartCount = 0;

    // Prepare word - make lower case and remove non-word characters
    word = word.toLowerCase().replace(/[^a-z]/g, '');

    // Specific common exceptions that don't follow the rule set below are handled individually
    // Array of problem words (with word as key, syllable count as value)
    var problemWords = {
        'simile': 3,
            'forever': 3,
            'shoreline': 2
    };

    // Return if we've hit one of those...
    if (problemWords.hasOwnProperty(word)) return problemWords[word];

    // These syllables would be counted as two but should be one
    var subSyllables = [
        /cial/,
        /tia/,
        /cius/,
        /cious/,
        /giu/,
        /ion/,
        /iou/,
        /sia$/,
        /[^aeiuoyt]{2,}ed$/,
        /.ely$/,
        /[cg]h?e[rsd]?$/,
        /rved?$/,
        /[aeiouy][dt]es?$/,
        /[aeiouy][^aeiouydt]e[rsd]?$/,
        /^[dr]e[aeiou][^aeiou]+$/, // Sorts out deal, deign etc
    /[aeiouy]rse$/ // Purse, hearse
    ];

    // These syllables would be counted as one but should be two
    var addSyllables = [
        /ia/,
        /riet/,
        /dien/,
        /iu/,
        /io/,
        /ii/,
        /[aeiouym]bl$/,
        /[aeiou]{3}/,
        /^mc/,
        /ism$/,
        /([^aeiouy])\1l$/,
        /[^l]lien/,
        /^coa[dglx]./,
        /[^gq]ua[^auieo]/,
        /dnt$/,
        /uity$/,
        /ie(r|st)$/];

    // Single syllable prefixes and suffixes
    var prefixSuffix = [
        /^un/,
        /^fore/,
        /ly$/,
        /less$/,
        /ful$/,
        /ers?$/,
        /ings?$/];

    // Remove prefixes and suffixes and count how many were taken
    prefixSuffix.forEach(function (regex) {
        if (word.match(regex)) {
            word = word.replace(regex, '');
            prefixSuffixCount++;
        }
    });

    wordPartCount = word.split(/[^aeiouy]+/ig)
        .filter(function (wordPart) {
        return !!wordPart.replace(/\s+/ig, '').length;
    })
        .length;

    // Get preliminary syllable count...
    syllableCount = wordPartCount + prefixSuffixCount;

    // Some syllables do not follow normal rules - check for them
    subSyllables.forEach(function (syllable) {
        if (word.match(syllable)) syllableCount--;
    });

    addSyllables.forEach(function (syllable) {
        if (word.match(syllable)) syllableCount++;
    });

    return syllableCount || 1;
};

function textStatistics(text) {
    return new TextStatistics(text);
}

在获取此函数并将其添加到 code 变量(参见 OP 的 Visual Basic 代码)后,我能够创建此控件的实例并调用其上的方法。在 VBA 中使用 TextStatistics 有几种不同的方法:

Dim wc, sc As Integer
Dim s1, s2, code As String
Dim oTextStats As Object
Dim o As New ScriptControl

code = "function cleanText(e){var t=['li','p','h1','h2','h3','h4','h5','h6','dd'];t.forEach(function(t){e=e.replace('</'+t+'>','.')});e=e.replace(/<[^>]+>/g,'').replace(/[,:;()\-]/,' ').replace(/[\.!?]/,'.').replace(/^\s+/,'').replace(/[ ]*(\n|\r\n|\r)[ ]*/,' ').replace(/([\.])[\. ]+/,'.').replace(/[ ]*([\.])/,'. ').replace(/\s+/,' ').replace(/\s+$/,'');e+='.';return e}function textStatistics(e){return new TextStatistics(e)}if(!Array.prototype.filter){Array.prototype.filter=function(e){'use strict';if(this===void 0||this===null){throw new TypeError}var t=Object(this);" & _
       "var n=t.length>>>0;if(typeof e!=='function'){throw new TypeError}var r=[];var i=arguments.length>=2?arguments[1]:void 0;for(var s=0;s<n;s++){if(s in t){var o=t[s];if(e.call(i,o,s,t)){r.push(o)}}}return r}}if(!Array.prototype.forEach){Array.prototype.forEach=function(e){var t=this.length;if(typeof e!='function')throw new TypeError;var n=arguments[1];for(var r=0;r<t;r++){if(r in this)e.call(n,this[r],r,this)}}}var TextStatistics=function(t){this.text=t?cleanText(t):this.text};" & _
       "TextStatistics.prototype.fleschKincaidReadingEase=function(e){e=e?cleanText(e):this.text;return Math.round((206.835-1.015*this.averageWordsPerSentence(e)-84.6*this.averageSyllablesPerWord(e))*10)/10};TextStatistics.prototype.fleschKincaidGradeLevel=function(e){e=e?cleanText(e):this.text;return Math.round((.39*this.averageWordsPerSentence(e)+11.8*this.averageSyllablesPerWord(e)-15.59)*10)/10};TextStatistics.prototype.gunningFogScore=function(e){e=e?cleanText(e):this.text;" & _
       "return Math.round((this.averageWordsPerSentence(e)+this.percentageWordsWithThreeSyllables(e,false))*.4*10)/10};TextStatistics.prototype.colemanLiauIndex=function(e){e=e?cleanText(e):this.text;return Math.round((5.89*(this.letterCount(e)/this.wordCount(e))-.3*(this.sentenceCount(e)/this.wordCount(e))-15.8)*10)/10};TextStatistics.prototype.smogIndex=function(e){e=e?cleanText(e):this.text;return Math.round(1.043*Math.sqrt(this.wordsWithThreeSyllables(e)*(30/this.sentenceCount(e))+3.1291)*10)/10};" & _
       "TextStatistics.prototype.automatedReadabilityIndex=function(e){e=e?cleanText(e):this.text;return Math.round((4.71*(this.letterCount(e)/this.wordCount(e))+.5*(this.wordCount(e)/this.sentenceCount(e))-21.43)*10)/10};TextStatistics.prototype.textLength=function(e){e=e?cleanText(e):this.text;return e.length};TextStatistics.prototype.letterCount=function(e){e=e?cleanText(e):this.text;e=e.replace(/[^a-z]+/ig,'');return e.length};TextStatistics.prototype.sentenceCount=function(e){e=e?cleanText(e):this.text;" & _
       "return e.replace(/[^\.!?]/g,'').length||1};TextStatistics.prototype.wordCount=function(e){e=e?cleanText(e):this.text;return e.split(/[^a-z0-9]+/i).length||1};TextStatistics.prototype.averageWordsPerSentence=function(e){e=e?cleanText(e):this.text;return this.wordCount(e)/this.sentenceCount(e)};TextStatistics.prototype.averageSyllablesPerWord=function(e){e=e?cleanText(e):this.text;var t=0,n=this.wordCount(e),r=this;e.split(/\s+/).forEach(function(e){t+=r.syllableCount(e)});return(t||1)/(n||1)};" & _
       "TextStatistics.prototype.wordsWithThreeSyllables=function(e,t){e=e?cleanText(e):this.text;var n=0,r=this;t=t===false?false:true;e.split(/\s+/).forEach(function(e){if(!e.match(/^[A-Z]/)||t){if(r.syllableCount(e)>2)n++}});return n};TextStatistics.prototype.percentageWordsWithThreeSyllables=function(e,t){e=e?cleanText(e):this.text;return this.wordsWithThreeSyllables(e,t)/this.wordCount(e)*100};TextStatistics.prototype.syllableCount=function(e){var t=0,n=0,r=0;e=e.toLowerCase().replace(/[^a-z]/g,'');" & _
       "var i={simile:3,forever:3,shoreline:2};if(i.hasOwnProperty(e))return i[e];var s=[/cial/,/tia/,/cius/,/cious/,/giu/,/ion/,/iou/,/sia$/,/[^aeiuoyt]{2,}ed$/,/.ely$/,/[cg]h?e[rsd]?$/,/rved?$/,/[aeiouy][dt]es?$/,/[aeiouy][^aeiouydt]e[rsd]?$/,/^[dr]e[aeiou][^aeiou]+$/,/[aeiouy]rse$/];var o=[/ia/,/riet/,/dien/,/iu/,/io/,/ii/,/[aeiouym]bl$/,/[aeiou]{3}/,/^mc/,/ism$/,/([^aeiouy])\1l$/,/[^l]lien/,/^coa[dglx]./,/[^gq]ua[^auieo]/,/dnt$/,/uity$/,/ie(r|st)$/];var u=[/^un/,/^fore/,/ly$/,/less$/,/ful$/,/ers?$/,/ings?$/];" & _
       "u.forEach(function(t){if(e.match(t)){e=e.replace(t,'');n++}});r=e.split(/[^aeiouy]+/ig).filter(function(e){return!!e.replace(/\s+/ig,'').length}).length;t=r+n;s.forEach(function(n){if(e.match(n))t--});o.forEach(function(n){if(e.match(n))t++});return t||1}"


s1 = "the quick brown fox jumps over the lazy dog"
s2 = "help me! Some Short sentence fragments. Just a test"

With o
    .Language = "JScript"
    .AddCode code
    ' Create a TextStatistics object initially with no text.
    ' textStatistics is a function that creates TextStatistics objects
    Set oTextStats = .Eval("textStatistics()")

    ' Now simply call TextStatistics methods directly
    wc = oTextStats.wordCount(s1)
    sc = oTextStats.sentenceCount(s2)

    ' Alternatively you can create a TextStatistics object with the text
    ' and call the methods with a blank string to return the values
    ' for the string passed in the constructor
    Set oTextStats = .Eval("textStatistics('" + s1 + "')")
    wc = oTextStats.wordCount("")
    sc = oTextStats.sentenceCount("")
End With

关于javascript - VBA JavaScript 对象不支持此属性或方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26037393/

相关文章:

javascript - 如何使用 Mocha 测试 Vue.js 中的 DOM 更新?

javascript - Array.size() 与 Array.length

vba - 如何在使用 sleep 时阻止 Excel 变得无响应

python - 将多个 CSV 转换为 xls 或 xlsx 并对它们应用格式

javascript - 将递归 jQuery For every 循环转换为 JavaScript 以进行 VBA 脚本控制

javascript - StompJS javascript 客户端在控制台上疯狂记录

javascript - PHP 后端与 JS xHTMLRequest 前端

excel - 某些工作表上出现运行时错误 '1004' : Method 'Range' of object 'Global' failed,,但我的代码能够在大多数其他工作表上运行?

ASP.Net ScriptControl - 从另一种方法调用一种方法

Javascript/Ajax - 手动从 Sys.EventHandlerList() 中删除事件处理程序