自动记账 自动记账
首页
指南
  • 参数错误
  • 为什么会读取我的聊天记录
  • 为什么云规则不支持一键导入
  • 无法同步账单
搞机工具
在线规则
意见反馈 (opens new window)
网盘 (opens new window)
  • Ankio (opens new window)
  • jsdelivr (opens new window)
💖支持
GitHub (opens new window)
首页
指南
  • 参数错误
  • 为什么会读取我的聊天记录
  • 为什么云规则不支持一键导入
  • 无法同步账单
搞机工具
在线规则
意见反馈 (opens new window)
网盘 (opens new window)
  • Ankio (opens new window)
  • jsdelivr (opens new window)
💖支持
GitHub (opens new window)
  • 序

    • 项目简介
    • 教程说明
  • 基础篇

    • 环境配置
    • 记账应用配置
    • 自动记账配置

      • 权限设置
      • 数据同步
      • 资产管理
      • 资产映射
      • 分类设置
      • 插件设置
  • 规则篇

    • 规则
    • 导入规则
    • 分享规则
    • 书写规则
  • 使用篇

    • 报销功能
    • WebDav备份
  • 进阶篇

    • 正则表达式
    • JavaScript
      • 概述
      • 内置参数
      • 内置函数
      • 示例代码
      • 网上的资源及教程
    • 日志
    • 调试模式
  • 问题篇

    • 参数错误
    • 为什么会读取我的聊天记录?
    • 为什么云规则不支持一键导入
    • 无法同步钱迹的数据
  • 其他

    • 贡献代码

      • 代码规范
      • Commit规范
      • PR提交规范
      • 微信适配
    • 更新日志
    • 开源协议

JavaScript

JS(JavaScript)作为一门编程语言,对于非计算机专业人士而言,有着较高的学习成本。其中内容非常庞大,以一个简单教程的体量无法阐述清楚。因此本章与其说是教程,不如说是对自动记账中的JS脚本进行一个说明。如果完全不懂JS的用户而言,建议不要使用JS脚本规则,或者直接抄作业。我会在之后放出一个示例,包含有详细的注释,大家可以直接复制代码。

如果想要进一步学习JavaScript,更深层次的了解它,可以前往以下几个网站学习:

  • W3School (opens new window)
  • 极客学院 (opens new window)
  • 菜鸟教程 (opens new window)
  • C语言中文网 (opens new window)
  • Bilibili知识区 (opens new window)

下面开始关于自动记账JS脚本的说明:

# 概述

在自动记账中,JS脚本主要用于自动分类。用于将账单自动划分类别,这一功能的实现是通过JS脚本,不论是可视化还是JS都是如此。可视化是由App自动生成一段JS代码,而JS模式则是由用户手动编写代码,本质上都是一样的。

在脚本中,所有的功能都是由函数实现,这里也不例外,一条规则就是一个函数,但这个函数的外壳function xxx() {...}已经被定义好,并且内置在app中,用户只需要编写函数内部的内容。而在运行规则时,App会调用该函数,注入参数后取得该函数的返回值。

注意

因此,书写JS规则时必须要有一个返回值,即return xxx。

# 内置参数

在规则运行的时候,App会向其中注入一些参数,在书写规则时可以直接调用这些参数,而参数之外的其他变量,则需要自行定义和赋值。

表1 - 内置参数表(点击展开/收起)
参数 说明
shopName 商户名称
shopRemark 商户备注
type 账单类型
hour 当前时间(小时)
minute 当前时间(分钟)
money 账单金额

# 内置函数

除内置参数以外,我们还提供了一个判定时间的内置函数isInTimeInner(minTime, maxTime,timeHour,timeMinute)。minTime 起始时间(如12:00), maxTime 终止时间(如15:05),timeHour 当前时,timeMinute 当前分。

调用方法,例如:

isInTimeInner("12:00", "12:30",hour,minute);

或者这样:

isInTimeInner("23:00", "6:30",hour,minute);

isInTimeInner()函数具体代码如下:

const isInTimeInner = function (minTime, maxTime,timeHour,timeMinute) {
    let regT = /([01\b]\d|2[0-3]):([0-5]\d)/;//限制范围00:00=>23:59
    const t1 = minTime.match(regT);
    const t2 = maxTime.match(regT);
    if(t1==null||t2==null||t1.length<3||t2.length<3){
        return false;
    }
    const h1 = t1[1], h2 = t2[1], m1 = t1[2], m2 = t2[2];
    if (h1 > h2)
        return (timeHour === h1 && timeMinute >= m1) || timeHour > h1 || timeHour < h2 || timeHour === h2 && timeMinute <= m2;
    else if (h1 < h2)
        return (timeHour === h1 && timeMinute >= m1) || (timeHour > h1 && timeHour < h2) || timeHour === h2 && timeMinute <= m2;
    else if (h1 === h2) {
        if (m1 < m2)
            return timeHour === h1 && timeMinute >= m1 && timeMinute <= m2;
        else if (m1 > m2)
            return (timeHour === h1 && timeMinute >= m1 || timeMinute <= m2) || (timeHour !== h1);
        else
            return m1 === m2 && timeMinute === m1 && timeHour === h1;
    }
};

# 示例代码

包罗万象,全能规则:(作者:太公摘花)

var sRemark = shopName + shopRemark + source,//将商户名、商户备注、账单来源整合为一个变量
    aRegs =//将收入和支出通用的放在外面
        // 理财收益
       [{"bkName":"余额(利)宝",   "reg":/(余[额利]宝).*收益/},
        {"bkName":"基金",         "reg":/基金.*收益/},
        {"bkName":"黄金",         "reg":/黄金.*收益/},
        {"bkName":"债券",         "reg":/债券.*收益/},
        {"bkName":"外汇",         "reg":/外汇.*收益/},
        {"bkName":"理财产品",     "reg":/理财产品.*收益/}
        ];
switch (type) {
    case "支出":
    case "报销":
        /*添加分类识别规则:这部分可以自行修改、添加或删除:基本格式为:{"bkName":"分类名","reg":"正则表达式"},注意:在中括号内添加。不懂正则表达式的不建议修改。*/
        var aOutRegs=
            /*三餐:                日常三餐的饮食,本分类将在后续分类中按时间进行拆分,分别输出为早餐、中餐、晚餐、夜宵。若不需要分开,后面会提供修改方法。*/ 
           [{"bkName":"三餐",      "reg": /[餐食饭炸烤蒸炒煨炖煮汤]|(粉|面|家菜)[店馆]|[包早]点|鲜包|(卤|螺蛳|牛肉|花甲)粉|(手工|拉|biangbiang|粉|刀削|牛肉)[面麵麺]|(家常|私房)菜|新芙蓉|沙县小吃|馄饨|饺子|麻辣|小吃|[鸡牛羊]排|肯德基|麦当劳|pizza|[披批比匹]萨|寿司|饿了么|美团订单|外卖/i},
            /*日常:                日常生活的消费,包含有一些常见的关键词。可以自行修改。*/
            {"bkName":"购物",      "reg": /七件事|超市|便利|.*客隆|家.*福|快乐惠|世纪联华|联华超市|大润发|华润万家|苏果|沃尔玛|物美|新一佳|好又多|华联|文峰大世界|TESCO乐购|易初莲花|麦德龙|中百连锁仓储|人人乐|家家悦|潍坊百货|欧尚|永辉|武商量贩|新华都|步步高商业|永旺|红旗连锁|三江购物|互惠|美廉美|百佳超市|易买得|维客|美特好|保龙仓|华普|利客来|良友金伴|美宜佳|华冠|家润多|华之友|好家乡|惠友|民生家乐|思达|雅家乐|天惠|新江厦|喜洋洋|乐尔乐/},
            {"bkName":"电器数码",  "reg": /手机|电脑|电视|冰箱|洗衣机|空调|NOKIA|诺基亚|MOTO|摩托罗拉|Samsung|三星|索尼爱立信|Apple|苹果|Philips|飞利浦|lenovo|联想|LGSharp|夏普|多普达|金立|Amoi|夏新|Bird|波导|纽曼|Haier|海尔|TCL|HP|惠普|BenQ|明基|OPPO|Konka|康佳|CECT|HEDY|七喜|CoolPAD|酷派|ASUS|华硕|Mio宇达电通|琦基|ZTE|中兴|MEIZU|魅族|UT斯达康|BlackBerry|黑莓|Alcatel|阿尔卡特|大显|HKC|弘谷电|艾美讯|amsam|恒基伟业|Palm|RIM|OKWAP|英华达|天语|小米|华为|一加|联想|OPPO|vivo|诺基亚|华硕|惠普|三星|索尼|金士顿|闪迪|七彩虹|英特尔|Intel|AMD|松下|美的|格力/i},
            {"bkName":"运动",      "reg": /健身|运动|瑜珈|增肌|keep/i},
            {"bkName":"房租",      "reg": /公寓/},
            {"bkName":"零食",      "reg": /奶茶|零食|[饮甜]品|果汁|星巴克|桥头排骨|烧仙草|茶颜悦色|喜茶|奈雪茶|蜜雪冰城|CoCo都可|一点点|乐乐茶|古茗|沪上阿姨|快乐柠檬/i},
            {"bkName":"快递",      "reg": /[快速][递运]|百世汇通|物流|宅急送/},
            {"bkName":"网购代付",  "reg": /亲[情属]卡/},
            {"bkName":"烟酒",      "reg": /[烟酒]|芙蓉王|大中华|红双喜|中南海|玉溪|红河|利群|金圣|野山茶|五粮液|茅台|国窖1573|[天海梦]之蓝|水井坊|剑南春|四特|稻花香|二锅头|马尿|老白干|波尔多|拉菲|黑桃A|[干甜][红白]|香槟|白兰地|伏特加|威士忌|纯生|乌苏|百威|雪津|雪花|乌苏|麦之初|科罗娜/i},
            /*定期缴费:            每月或每段时间相对固定的消费*/
            {"bkName":"党费会费",  "reg": /(会|党)费/},
            {"bkName":"话费网费",  "reg": /电信|联通|移动/},
            {"bkName":"水电煤",    "reg": /[电水]费|(燃|液化)气/},
            {"bkName":"保险",      "reg": /保[险单]|相互宝/},
            /*形象工程:            穿着打扮等外在形象的消费。*/
            {"bkName":"穿戴",      "reg": /[衣裤鞋袜帽穿戴]|[男女]装|牛仔|耐克|nike|阿迪|361[度°]|鸿星尔克|特步|李宁|美特斯邦威|优衣库|以纯/i},
            {"bkName":"理发",      "reg": /发廊|美发/},
            {"bkName":"护肤美妆",  "reg": /洗面奶|面膜|卸妆[水棉油膏]|口红|防晒|(水|润肤|身体)乳|(眼|护手)霜|爽肤|精[华油]|[乳唇]膏|凝胶|祛痘|(果|水杨)酸|粉底|欧莱雅|施华蔻|雅诗.*兰黛/},
            /*虚拟消费:            支持正版,虚拟内容付费。这里缺游戏类分类,主要因为微信提取到的账单备注无法支持识别。*/
            {"bkName":"付费会员",  "reg": /加速器|(1号|畅读|影城)卡|[^蚁]会员|QQ(美化|号)|vip|迅雷|爱奇艺|优酷|腾讯视频/i},
            {"bkName":"购买App",   "reg": /软件.*安装|(激活|注册)码|([高升]级|专业|付费|终[生身级]|增强|完整|永久)版|\bP(ro|lus)\b/i},
            {"bkName":"游戏",      "reg": /游戏|game|Steam|育碧|点券/i},
            {"bkName":"小说漫画",  "reg": /阅读|漫画|[看读追]书|小说|起点|多看/},
            /*娱乐:                生活需要娱乐,电影、旅行、玩耍、泡吧,后续将完善分类。*/
            {"bkName":"电影",      "reg": /影[城院]|(电影|淘票)票|猫眼电影|中影|王府井|cgv|潇湘国际/i},
            {"bkName":"旅行",      "reg": /旅[游行社馆]|[青国]旅|酒店|宾馆|招待所|维也纳国际|凯宾斯基|华天|7天|如家/},
            {"bkName":"打赏",      "reg": /直播|虎牙|斗鱼|抖音/},
            {"bkName":"聚会",      "reg": /KTV/i},
            /*非常规消费:          这些消费并不常有,而且金额、频率存在较大的不确定性*/
            {"bkName":"医疗",      "reg": /医(院|馆|.?室)|药[店房号]|诊所|卫生(服务(中心|站)|[院所室])/},
            {"bkName":"学习",      "reg": /打印|课程|教[材辅育程你]|讲[解义]|学会|入门到精通|慕课|学院|医视时代|医脉通|新东方在线|潭州课堂沪江小D/i},
            {"bkName":"罚款",      "reg": /交警|公安|法院/},
            /*交通:                出行的交通费用,这里将最常用且可以通用的地铁和公交合并在一起,买车、养车和加油也算在了一起。*/
            {"bkName":"公交/地铁", "reg": /雪球科技|地铁|公交/},
            {"bkName":"打车",      "reg": /滴滴|高德|出租车|的士|打的|代驾/},
            {"bkName":"火车",      "reg": /铁路|火车|高铁|列车/},
            {"bkName":"飞机",      "reg": /航[空班]|机票/},
            {"bkName":"汽车/加油", "reg": /汽车|加油站|石[油化]|海油|通用|大众|五菱|依维柯|荣威|申沃|东风|雪铁龙|本田|霸龙|悦达起亚|风神|小康|一汽|解放|奥迪|丰田|红旗|马自达|夏利|佳宝|北汽|现代|福田|Jeep|奔驰|宝马|雷诺|特斯拉|法拉利|宾利|保时捷|兰博基尼|劳斯莱斯|欧曼|昌河|绅宝|威旺|欧辉|广汽|传祺|三菱|菲亚特|客车|吉奥|日野|长安商用|哈飞|陆风|标致/i},
            /*育儿:                主要添加了母婴产品和童装品牌,如有其他可私信我提供关键词*/
            {"bkName":"育儿",      "reg": /童装|儿.*奶粉|纸尿裤|玩具|奥特曼|母婴|Balabala|巴拉巴拉|小猪班纳|安奈儿|BOBDOG|巴布豆|米妮·哈鲁|MiniZaru/i},
            /*红包和转账:          各种转账和红包*/
            {"bkName":"发红包",    "reg":/(红包|转账)给别人/}
           ];
        aRegs=aRegs.concat(aOutRegs);
        aOutRegs = null;
        break;
    case "收入":
        var aInRegs =//收入的分类规则:
           [{"bkName":"工资",      "reg":/(工资|津贴)/},
            {"bkName":"收红包",    "reg":/收.*(红包|转账)/}
           ];
        aRegs=aRegs.concat(aInRegs);
        aInRegs = null;
        break;
    default :
        aRegs=[];
        break;
}
/*
通过for循环语句,逐条验证规则。
*/
var sBook;//[不需要三餐分开的可以删除本行]定义一个sBook变量存放分类,以便对一些特殊分类进行进一步处理。
for (var i = 0 ,len = aRegs.length ; i<len; i++) {
    if (aRegs[i].reg.test(sRemark))
    /*不需要三餐按时间分开的,
    请进行以下操作:
    1、将这条注释之后的所有代码删除(必须)
    2、删除上一条注释标注的代码(非必须)
    3、删除后在这条注释后添加这行代码:(必须)
        return aRegs[i].bkName;}
    这样就可以结束了。*/
    {
        sBook = aRegs[i].bkName;
        i=sRemark=aRegs=null;//回收变量,这些变量使用到此结束
        break;
    }
}
/*以下内容为根据时间将三餐分开*/
switch (sBook) {     //通过sBook值选择操作,使用Switch语句性能比if语句高。
    case "三餐":    //将三餐单列:按时间分类,使用isInTimeInner()函数判定。
        if      (isInTimeInner("06:00", "09:39", hour, minute)) return "早餐";
        else if (isInTimeInner("09:40", "15:44", hour, minute)) return "午餐";
        else if (isInTimeInner("15:45", "21:29", hour, minute)) return "晚餐";
        else if (isInTimeInner("21:30", "05:59", hour, minute)) return "夜宵";
        break;
    default :
        return sBook;
}

# 网上的资源及教程

  • W3School (opens new window)
  • 极客学院 (opens new window)
  • 菜鸟教程 (opens new window)
  • C语言中文网 (opens new window)
  • Bilibili知识区 (opens new window)
    • 黑马程序员JavaScript全套教程,Web前端必学的JS教程,零基础入门JavaScript (opens new window)
    • 尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通) (opens new window)
    • JavaScript速成课【油管最火JS教程】 (opens new window)
上次更新: 2022/02/24, 10:24:12
正则表达式
日志

← 正则表达式 日志→

Theme by Vdoing | Copyright © 2020-2022 Ankio | GPL3.0 License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式