有时我们需要对易语言编辑框的文本,进行字数统计,方法有很多,但要做到实时统计,要求处理速度够快,(如,代码写在编辑框内容被改变事件下,有两种情况会造成该事件触发非常快,一是长按粘贴快捷键内容疯狂增加,二是长按退格键,内容频频减少)本人测试这两种行为触发内容被改变的频率是20多30毫秒左右,就是说,如果统计字数的子程序执行一次超过这个时间,程序就会卡顿。这里列出三个方法及测试,你可根据自己的需要选择。代码数据全部基于编辑框内容被改变事件下测试,并没有用时钟及点击按钮的方式。
工具/原料
电脑
易语言及相关支持库(易自带,为方便,可全部勾选)
方法/步骤
1、土法实现1-1用易自带最基本的几个命令实现,相对实现简单,字数上限最好在4万以下,仅支持ANSI编码文本,不支持Unnicode编码。因为文本在ansi编码下,所有字符转换到全角都占用两个字节,取其长度除2就是字符数。
2、1-2土法代码如下:.版本2.支持库spec.支持库iext.子程序笨办法统计字数,,,用易自带基本命令实现.局部变量全字数,文本型,,,去除了空格、和回车的所有字符数。.局部变量时间,整数型时间=取整(取启动时间())全字数=到文本(取整(取文本长度(子文本替换(到全角(删全部空(编辑框1.内容)),到全角(#换行符),“”,,,假))÷2))调试输出(“用时”,取整(取启动时间()-时间),“字数”,全字数)状态条1.置文本(1,全字数)
3、JScript脚本命令调用,下面是效果图。2-1执行速度快了不少,用正则实现统计中文字数的统计。这个是单线程模式。当然也可以用易的脚本组件来调用。此法字数不要超过24万左右,否则同样会卡顿。
4、2-2JScript脚本命令代码如下:.版本2.支持库spec.支持库iext.子程序取字符串长度.局部变量JS脚本,对象,,,JScript.局部变量时间,整数型.局部变量全字数,文本型.局部变量中文字数,文本型时间=取整(取启动时间())JS脚本.创建(“ScriptControl”,)JS脚本.写属性(“Language”,“JScript”)JS脚本.数值方法(“ExecuteStatement”,#JS命令)全字数=JS脚本.通用方法(“Run”,“求字数全”,编辑框1.内容).取文本()中文字数=JS脚本.通用方法(“Run”,“求字数中文”,编辑框1.内容).取文本()调试输出(“用时”,取整(取启动时间()-时间),“字数”,全字数)状态条1.置文本(1,全字数)状态条1.置文本(3,中文字数)需增加个长文本常量这里命名为:#JS命令内容在下一步。
5、2-3JScript脚本命令长文本常量:#JS命令内容如下:function求字数全(参1){参1=参1.replace(newRegExp("","gm"),"")//先删全部空格return参1.replace(newRegExp("[\n\r]+","gm"),"").length;//再删换行求字数};function求字数中文(参1)//删去所有非中文求字数。{return参1.replace(newRegExp("[^\u4e00-\u9fa5]+","gm"),"").length;};function删除指定文本(参1,参2)//参数2可以是表达式{return参1.replace(newRegExp(参2,"gm"),"");};
6、多线程js方式。3-1易在多线程下调用JS脚本,会没有任何效果,返回空文本或返回0。解决办法是增加两个dll能解决(CoUninitialize和CoInitialize)运行是正常了,但新问题又来了,多线程成单线程。百度是这样解释这对夫妻DLL(必须配对使用)的:CoInitialize告诉Windows以单线程的方式创建com对象。经过测试也确实是这样,同时启动多个线执行简单代码,程序立刻死掉。最终,解决办法是,用类模块方式。插入两个DLL,代码如下:.版本2.DLL命令卸载COM,,"ole32.dll","CoUninitialize",,卸载COM同加载COM配对使用.DLL命令加载COM,,"ole32.dll","CoInitialize",,加载COM告诉Windows以单线程的方式创建com对象,解决多线程内JS脚本代码无效问题.参数pvReserved,整数型,,值为0
7、3-2选探怙鲔译择易主菜单-插入-类模块,点击,并把下面的代码粘贴进刚刚新建的类模块注:粘贴前删除两个默认子程序_初始化和_销毁防止重复。粘贴完修观鲼视防改一下类名。代码如下:.版本2.程序集JS脚本类模块.程序集变量JS脚本,对象.子程序_初始化,,,当基于本类的对象被创建后,此方法会被自动调用,加载COM(0)JS脚本.创建(“ScriptControl”,)JS脚本.写属性(“Language”,“JScript”).子程序_销毁,,,当基于本类的对象被销毁前,此方法会被自动调用JS脚本.清除()卸载COM().子程序脚本语言,文本型,公开,设置或获取脚本引擎解释的语言,可供选择的属性值:JScriptVBScript.参数语言名,文本型,可空,如果,提供的参数文本,既不等于JScript也不等于VBScript会设置为JScript.判断开始(是否为空(语言名)=真)返回(JS脚本.读文本属性(“Language”,)).默认.如果真(语言名≠“JScript”且语言名≠“VBScript”)语言名=“JScript”.如果真结束返回(到文本(JS脚本.写属性(“Language”,语言名))).判断结束.子程序超时,整数型,,Timeout,设置或返回时间(毫秒),此时间后用户可选择中止脚本代码的执行或允许代码继续执行。.参数欲写入属性值,整数型,可空,-1表示直到执行完才返回。.判断开始(是否为空(欲写入属性值)=真)返回(JS脚本.读数值属性(“Timeout”,)).默认返回(到整数(JS脚本.写属性(“Timeout”,欲写入属性值))).判断结束.子程序错误信息,对象,公开,Error如果脚本执行出错返回出错说明。返回(JS脚本.读对象型属性(“Error”,)).子程序脚本执行,整数型,公开,ExecuteStatement,返回0为执行正常,返回非0为出错,错误信息可以从“错误码信息”属性中取得。本命令为初级对象成员命令。.参数Statement,文本型,,包含要执行的脚本代码,如为空则默认为执行上次的脚本代码。如果脚本代码中包括函数或过程,执行此方法后可以用“运行”方法来单独执行。返回(JS脚本.数值方法(“ExecuteStatement”,Statement)).子程序脚本运行,文本型,公开,Run,如有返回值返回相应文本,否则返回空文本。本命令为初级对象成员命令。命令参数表中最后一个参数可以被重复添加。.参数ProcedureName,文本型,,所要运行的过程或函数名。.参数P1,文本型,可空,可以被扩展。.参数P2,文本型,可空.参数P3,文本型,可空.参数P4,文本型,可空.参数P5,文本型,可空.参数P6,文本型,可空.参数P7,文本型,可空.参数P8,文本型,可空.判断开始(是否为空(P1)=真)返回(JS脚本.通用方法(“Run”,ProcedureName).取文本()).判断(是否为空(P2)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1).取文本()).判断(是否为空(P3)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2).取文本()).判断(是否为空(P4)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3).取文本()).判断(是否为空(P5)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4).取文本()).判断(是否为空(P6)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4,P5).取文本()).判断(是否为空(P7)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4,P5,P6).取文本()).判断(是否为空(P8)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4,P5,P6,P7).取文本()).默认返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4,P5,P6,P7,P8).取文本()).判断结束
8、3-3创建一个进入许可证,用于多线程向状态条写入字数数据。创建多线程统计字数子程序,代码如下:.版本2.支持库spec.支持库EThread.支持库iext.子程序多线程统计字数.局部变量时间,整数型.局部变量文本,文本型.局部变量全字数,文本型,,,去除了空格、和回车的所有字符数。.局部变量中文字数,文本型,,,只统计纯中文(标点符号也不统计在内).局部变量脚本,JS脚本类模块时间=取启动时间()脚本.脚本执行(#JS命令)全字数=脚本.脚本运行(“求字数全”,编辑框1.内容)中文字数=脚本.脚本运行(“求字数中文”,编辑框1.内容)调试输出(“用时”,取整(取启动时间()-时间),“字数”,全字数)进入许可区(许可证一字数显示操作)'许可证作用:防止多线程在同一时刻,写组件属性(等同于变量)。状态条1.置文本(1,全字数)状态条1.置文本(3,中文字数)退出许可区(许可证一字数显示操作)
9、在编辑框1.内容被改变事件下写下代码:启动线程(&多线程统计字数,,)'这里并没有提供线程句柄参数,目的是让易内部处理线程句柄。至此,大功告成。
方法/步骤2
1、最近有朋友反应,写出一模一样的程序,却不统计字数,由于我的原程序没了,我试着还原,还确实费了些功夫。原因是从经验页面复制到易语言窗口,程序会出现错误,其实就是文本格式以及换行的问题。我尝试了一下,复制易代码到记事本,然后再从记事本复制粘贴到经验里边就不会出现问题。下边我把整个代码用这种方法按几个部分粘贴在下面,需要的朋友可以直接复制到易语言。把这部分列为第4部分,前面的也不改动了,此部分方便快速建立完整的测试程序。4-1界面这部分无法复制。如下图1个编辑框是否允许多行设置为真其它根据自己喜好3个单选框用于测试3个方法。1个状态条添加6个项目,并将0、4项目按下图设置好文字。状态条用于显示测试数据,不建议用调试输出,字数太多的情况下,调试输出会占用过多资源。
2、4-2DLL插入一条新的DLL,如DLL命令1,选中它,然后把下面文本粘贴上去。.版本2.DLL命令卸载COM,,"ole32.dll","CoUninitialize",,卸载COM同加载COM配对使用.DLL命令加载COM,,"ole32.dll","CoInitialize",,加载COM告诉Windows以单线程的方式创建com对象,解决多线程内JS脚本代码无效问题.参数pvReserved,整数型,,值为0
3、4-3常瞠饨土椿量注意事项:不要添加成普通常量。1.进入常量界面,单击右键。并从右键菜单中选择新长文本常量,创建一个长文本常量。并将常量名改名:JS命令2.双击夼猿勇麒JS命令常量值部分(此时显示为:<文本长度:0>)进入:请输入文本窗口。3.把下边内容粘贴到请输入文本窗口确认后自动退出请输入文本窗口。function求字数全(参1){参1=参1.replace(newRegExp("","gm"),"")//先删全部空格return参1.replace(newRegExp("[\n\r]+","gm"),"").length;//再删换行求字数};function求字数中文(参1)//删去所有非中文求字数。{return参1.replace(newRegExp("[^\u4e00-\u9fa5]+","gm"),"").length;};function删除指定文本(参1,参2)//参数2可以是表达式{return参1.replace(newRegExp(参2,"gm"),"");};4.此时,JS命令常量值部分显示为:<文本长度:393>参考下图
4、4-4类喋碾翡疼模块1.点击易语言插入菜单,选择类模块如:类12.把类1下的两个默认添加的2个方法,忧溲枷茫_初始化和_销毁删除,只留下一个类头部。3.把类1名称改为:JS脚本类模块4.由于粘贴不会生成类成员,需要自行添加1个类成员点击JS脚本类模块名称位置,然后回车,在私有成员名输入:JS脚本类型输入对象。4.把下面代码粘贴在JS脚本类模块下面【参考下图:】.版本2.程序集JS脚本类模块.子程序_初始化,,,当基于本类的对象被创建后,此方法会被自动调用,加载COM(0)JS脚本.创建(“ScriptControl”,)JS脚本.写属性(“Language”,“JScript”).子程序_销毁,,,当基于本类的对象被销毁前,此方法会被自动调用JS脚本.清除()卸载COM().子程序脚本语言,文本型,公开,设置或获取脚本引擎解释的语言,可供选择的属性值:JScriptVBScript.参数语言名,文本型,可空,如果,提供的参数文本,既不等于JScript也不等于VBScript会设置为JScript.判断开始(是否为空(语言名)=真)返回(JS脚本.读文本属性(“Language”,)).默认.如果真(语言名≠“JScript”且语言名≠“VBScript”)语言名=“JScript”.如果真结束返回(到文本(JS脚本.写属性(“Language”,语言名))).判断结束.子程序超时,整数型,,Timeout,设置或返回时间(毫秒),此时间后用户可选择中止脚本代码的执行或允许代码继续执行。.参数欲写入属性值,整数型,可空,-1表示直到执行完才返回。.判断开始(是否为空(欲写入属性值)=真)返回(JS脚本.读数值属性(“Timeout”,)).默认返回(到整数(JS脚本.写属性(“Timeout”,欲写入属性值))).判断结束.子程序错误信息,对象,公开,Error如果脚本执行出错返回出错说明。返回(JS脚本.读对象型属性(“Error”,)).子程序脚本执行,整数型,公开,ExecuteStatement,返回0为执行正常,返回非0为出错,错误信息可以从“错误码信息”属性中取得。本命令为初级对象成员命令。.参数Statement,文本型,,包含要执行的脚本代码,如为空则默认为执行上次的脚本代码。如果脚本代码中包括函数或过程,执行此方法后可以用“运行”方法来单独执行。返回(JS脚本.数值方法(“ExecuteStatement”,Statement)).子程序脚本运行,文本型,公开,Run,如有返回值返回相应文本,否则返回空文本。本命令为初级对象成员命令。命令参数表中最后一个参数可以被重复添加。.参数ProcedureName,文本型,,所要运行的过程或函数名。.参数P1,文本型,可空,可以被扩展。.参数P2,文本型,可空.参数P3,文本型,可空.参数P4,文本型,可空.参数P5,文本型,可空.参数P6,文本型,可空.参数P7,文本型,可空.参数P8,文本型,可空.判断开始(是否为空(P1)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1).取文本()).判断(是否为空(P2)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2).取文本()).判断(是否为空(P3)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3).取文本()).判断(是否为空(P4)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4).取文本()).判断(是否为空(P5)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4,P5).取文本()).判断(是否为空(P6)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4,P5,P6).取文本()).判断(是否为空(P7)=真)返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4,P5,P6,P7).取文本()).默认返回(JS脚本.通用方法(“Run”,ProcedureName,P1,P2,P3,P4,P5,P6,P7,P8).取文本()).判断结束
5、4-5启咿蛙匆盗动窗口程序集部分1.进入启动窗口程序集,删除所有内容(包括启动窗口创建完毕事件子程序),只留一个程序集中的头部。2.同粘贴模块的私有成员名一样,程序集的变量名是粘贴不上说湫鲆胪去的。这里特别说明下,从一个易程序复制粘贴到另一个易程序是完美没有任何问题的。所以,先自行添加一个程序集变量变量名:许可证一字数显示操作类型:整数型留空默认就是整数型2.把下面内容粘贴到启动窗口程序集。.版本2.支持库EThread.支持库iext.程序集窗口程序集_启动窗口.程序集变量许可证一字数显示操作,整数型.子程序__启动窗口_创建完毕许可证一字数显示操作=创建进入许可证().子程序__启动窗口_将被销毁删除进入许可证(许可证一字数显示操作).子程序笨办法统计字数,,,用易自带基本命令实现.局部变量全字数,文本型,,,去除了空格、和回车的所有字符数。.局部变量时间,整数型.局部变量全字数,整数型.局部变量时间,整数型时间=取整(取启动时间())全字数=取整(取文本长度(子文本替换(到全角(删全部空(编辑框1.内容)),到全角(#换行符),“”,,,假))÷2)状态条1.置文本(1,到文本(全字数))状态条1.置文本(5,到文本(取整(取启动时间()-时间))).子程序JS计算文本长度.局部变量JS脚本,对象,,,JScript.局部变量时间,整数型.局部变量全字数,文本型.局部变量中文字数,文本型时间=取整(取启动时间())JS脚本.创建(“ScriptControl”,)JS脚本.写属性(“Language”,“JScript”)JS脚本.数值方法(“ExecuteStatement”,#JS命令)全字数=JS脚本.通用方法(“Run”,“求字数全”,编辑框1.内容).取文本()中文字数=JS脚本.通用方法(“Run”,“求字数中文”,编辑框1.内容).取文本()状态条1.置文本(1,全字数)状态条1.置文本(3,中文字数)状态条1.置文本(5,到文本(取整(取启动时间()-时间))).子程序多线程统计字数.局部变量时间,整数型.局部变量文本,文本型.局部变量全字数,文本型,,,去除了空格、和回车的所有字符数。.局部变量中文字数,文本型,,,只统计纯中文(标点符号也不统计在内).局部变量脚本,JS脚本类模块时间=取启动时间()脚本.脚本执行(#JS命令)全字数=脚本.脚本运行(“求字数全”,编辑框1.内容)中文字数=脚本.脚本运行(“求字数中文”,编辑框1.内容)进入许可区(许可证一字数显示操作)'许可证作用:防止多线程在同一时刻,写组件属性(等同于变量)。状态条1.置文本(1,全字数)状态条1.置文本(3,中文字数)状态条1.置文本(5,到文本(取整(取启动时间()-时间)))退出许可区(许可证一字数显示操作).子程序_编辑框1_内容被改变.判断开始(单选框土法统计.选中=真)清空状态条()笨办法统计字数().判断(单选框JS统计.选中=真)清空状态条()JS计算文本长度().默认清空状态条()启动线程(&多线程统计字数,,).判断结束.子程序清空状态条状态条1.置文本(1,“”)状态条1.置文本(3,“”)状态条1.置文本(5,“”)
6、好了,测试是OK的