1

我试图从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 日最终工作 VBA 版本感谢 Michael Petch

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
4

1 回答 1

2

今天下午我花了一些时间学习 Javascript,然后试图弄清楚你的TextStatistics类在 Microsoft 的ScriptControl对象中运行时发生了什么。我没有从 VBA 中的损坏代码开始,而是回到了 OP 引用的github中的代码。我发现的第一件事是 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。一旦我明白了这一点,我就找到了一个包含此信息的链接,其中包括以下评论:关于该forEach方法:

此方法是对 ECMA-262 标准的 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);
        }
    };
}

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

在第 5 版中将过滤器添加到 ECMA-262 标准中;因此,它可能不会出现在标准的所有实现中。您可以通过在脚本开头插入以下代码来解决此问题,允许在本机不支持它的 ECMA-262 实现中使用过滤器。

提供的符合规范的代码:

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 代码),我能够创建此控件的实例并在其上调用方法。TextStatistics在 VBA中有几种不同的使用方法:

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
于 2014-09-30T23:43:45.833 回答