zoukankan      html  css  js  c++  java
  • 集算器如何处理文本计算——无结构运算

    文本可以说是除了数据库外几乎最常见的数据存储形式,针对文本的计算非常重要。然而文本本身没有计算能力,不象数据库有SQL语法,这样对文本的计算就需要借助程序设计语言编码,而大多数用于文本处理的程序语言都没有集合化的,编写批量运算时很繁琐。比如用Java写个很简单地求和运算就要很多行,如果涉及到过滤分组这种运算就需要几百行代码。近年来新出来的perl,python,R等脚本语言在这些方面有所改善,但对批量结构化计算的支持仍然不足,而且集成性也较差。

    还有一种方案是将文本数据导入数据库再利用SQL计算,但文本经常缺乏数据库要求的强数据类型特征,导入过程常常要伴随繁琐的数据整理,而且多了一个步骤,事务的处理效率也会受到严重影响。

    作为集合化的动态脚本语言,集算器一定程度地弥补这方面的缺失。这里将列举一些文本计算中常见的情况,说明集算器实施这类计算的优势。

    无结构运算

    文本解析

    文本T.txt的行内数据项由不确定数量的空格分隔开:

    20010-8-13 991003 3166.63 3332.57  3166.63  3295.11

    2010-8-10 991003 3116.31 3182.66  3084.2   3140.2

    ……

    现在要计算每行最后四项数据的平均值列表。用集算器只要一句:

            

    A

    1

    =file("T.txt").read@n().(~.array@tp(“”).to(-4).avg())

    read@n()将文本读入成字串集合,array@t(“”)将字串按不定数量的空白符拆成子串集合,@p将自动解析成合适的数据类型以便进一步计算(这里计算平均)。

    将逗号分隔符文本T.csv中行内数据项数不少于8项的行的前8项写出成另一个文本R.txt,分隔符替换成|(某些银行系统采用的分隔符):

            

    A

    1

    =file("T.csv").read@n().(~.array(“,”)).select(~.len()>=8)

    2

    >file(“R.txt”).write(A1.(~.to(8).string(“|”)))

    string()函数可将集合按指定分隔符再拼成字串。

    文本T.txt中都是形如下行的串,需要按字符US前的州名(LA)分组拆分成多个文件。

    COOP:166657,'NEW IBERIA AIRPORT ACADIANA REGIONAL LA US',200001,177,553

    ……

            

    A

    1

    =file("T.txt").read@n()

    2

    =A1.group(mid(~,pos(~," US'")-2,2):state;~:data)

    3

    >A2.run(file(state+".txt").export(data))

    集算器也提供了对正则表达式的支持以应对复杂的拆解需求。不过由于正则表达式的使用难度较大且性能较差,一般建议仍然用常规方法实现。

    结构化

    日志S.log中每3行构成一段完整信息,需要将其解析成结构化数据后再到T.txt:

            

    A

    B

     C

    1

    =file(“S.log”).read@n()

    2

    =create(…)

    建立目标结果集

    3

    for A1.group((#-1)3)

    按行号分组,每3行一个单位

    从A3(这3行)中解析出字段值

    >A2.insert(…)

    插入到目标结果集

    >file(“T.txt”).export(A2)

    写出结果

    有了按行号分组的机制,就可以用循环每次处理一组数据,简化难度。

    显然,更简单的单行情况是其特例。

    如果S.log大到不能读入内存,也可以使用游标逐步读入并写出:

            

    A

    B

    1

    =file(“S.log”).cursor@si()

    创建游标用流式读入文件

    2

    =file(“T.txt”)

    结果文件

    3

    for A1,3

    每读入3行执行一轮循环

    从A3(这3行)中解析出字段值

    >A2.export@a(...)

    追加写到文件中

    熟悉的用户还可以优化代码,使得解析多条记录后一次写出,会有更好的性能。

    日志S.log中每段完整信息均以”---start---“开头,包含行的数量不确定。这时只要将前面的A3格改成:

    3

    for A1.group@i(~==”---start---”)

    出现---start---时会产生一个新分组

    类似地,大文本时也可以用游标处理,也是将上面A3格改成:

    3

    for A1;~==”---start—“:0

    出现---start---时另起一轮循环

    不定行还有一种情况,同一段信息的每一行都有相同的前缀(比如该段日志所属的用户号等),当这个前缀发生变化时就表示开始另一段信息了,这时仍然只要简单地修改A3代码即可处理:

    3

    for A1.group@o(left(~,6))

    前6个字符变化时产生一个新组

    3

    for A1;left(~,6)

    前6个字符变化时另起一轮循环

    前一小节的运算也可以改造成使用游标支持大文本。

    查找统计

    在目录下所有文本中找出含有指定单词的文件,并列出所在行内容及行号:

            

    A

    1

    =directory@p(“*.txt”)

    2

    =A1.conj(file(~).read@n().(if(pos(~,"xxx"),[A1.~,#,~].string())).select(~))

    grep是常用的unix命令,但有些操作系统下没有,且在程序中实现也不简单。集算器提供了文件系统的遍历功能,结合文本计算能力,只要两句代码就能完成。

    列出文本T.txt中所有出现过的单词及次数,忽略大小写:

            

    A

    1

    =lower(file(“T.txt”).read()).words().groups(~:word;count(1):count)

    WordCount是著名的练习题,集算器提供了words()函数将串拆分成单词,只要一句就可以完成这个运算。

    列出文本T.txt包括字母a,b,c的所有单词,忽略大小写:

            

    A

    1

    =lower(file(“T.txt”).read()).words().select(~.array(“”).pos([“a”,”b”,”c”]))

    由于次序问题,判断字母包含不能用子串查找,要用array(“”)将串拆成单字符集合,再用集合从属去判断。有集合运算支持的集算器也只要一句即可。

    这些运算都可以用分段或游标的方式简单改造以支持大文本。

  • 相关阅读:
    各类免费资料及书籍索引大全(珍藏版)
    转—如何写一篇好的技术博客
    如何写技术博客
    Spring + Spring MVC + Mybatis 框架整合
    Httpclient 4.5.2 请求http、https和proxy
    HttpClient4.5.2 连接池原理及注意事项
    php加密数字字符串,使用凯撒密码原理
    php 阿里云视频点播事件回调post获取不到参数
    Nginx代理后服务端使用remote_addr获取真实IP
    记录:mac的浏览器访问任何域名、网址都跳转到本地127.0.0.1或固定网址
  • 原文地址:https://www.cnblogs.com/raqsoft/p/4904457.html
Copyright © 2011-2022 走看看