2020/7/7 edit: 这篇文章的参考意义不大,事实上这篇文章所涉及的所有内容使用表格软件本身自带的功能都可以实现,只是写这篇文章的时候自己并不熟悉表格软件(毕竟平时几乎不和表格软件打交道)所以误以为一些功能需要手动实现,所以才有了这篇文章…

我的第二份工作入职在即,而这一次则真的是完全跑到了一个陌生的城市了。租房,购置相关用品,还尚未工作钱就花掉一堆。尽管我个人之前一直都没有过记账的习惯,但为了让自己能够搞清楚自己的钱都花在哪里了,于是还是决定整个超级无敌无脑简单的账本出来。

顺带一提,这篇文章仅仅是写下来记录一下整个过程,其实整个文章并没有多高的技术含量。如果你熟悉 Excel vba 或者 Google Spreadsheets 脚本的编写而又期望学习一些新的技巧的话,这篇文章不是你想要的文章。

尽管很水,但鉴于这篇文章好歹和技术稍微挂点钩,所以这篇文章我同时发布在了 Cnblogs 上,不过 Cnblogs 上的文章自然是少一点关于日常的事情。

搞的就这玩意儿

(注:上图的数据非真实数据)

选型?

首先决定的就是搜索现有的账本工具,而发现一部分账本软件过于复杂,另一部分则是使用他们自己的云服务去存储这些信息。由于感觉自己的需求的确很简单,只需要简单的支出收入计算就可以满足,故最终选择不使用复杂的记账平台和软件。

收入支出计算,差不多就是一个 Excel 就能做到的事情,故开始考虑直接使用 Excel 表格加 vba 来辅助完成工作。但考虑到我平时需要使用手机处理事情,以及曾经被Excel Online的用户体验“感动”过,我决定使用另一家的服务来做这件事,也就是 Google Spreadsheets 。

开发?

不同于以往写小工具的时候的复杂需求和复杂流程,如果选择使用表格软件完成这个记账任务其实只需要在指定的单元格填填东西编写公式就好了。于是填写好列的表头:时间,内容,数值变动,变动后结果和备注。然后就完事儿了。

作为账本,需要自动计算的东西其实就两个,即从初始金额开始每次数值变动后的“变动后结果”,以及当前页账本整个算下来的余额。而这两个需求其实也非常简单,只需要公式即可完成。其中整页余额只需要找个格子写个 SUM(C4:C200) (假设变动的值从在C列,从行4开始,计算到4到200行值的和)把变动的值加一块儿就行了。而计算当前行金额变动后的结果也很简单,只需把上一行的结果和这一行变动的数值相加即可。在我的这个例子中,即当前单元格的值为这个单元格上方的值加上这个单元格左方的值,即公式 =INDIRECT("R[-1]C[0]",false)+INDIRECT("R[0]C[-1]",false) 。Tada!一个无脑账本就这么完成了(你什么都没做啊喂!)。

就这么结束了?

由于如果仅仅如此的话,一切的确太过简陋以至于连一篇博客也水不完, 于是还是决定加一点东西进去,即按照颜色标识收入和支出,而这就需要编写简单的脚本处理了。事实上,相比正常的软件开发,这个需求也显得过于简单,所以我们很容易就能得到这种伪代码:

if (这次花的钱钱 > xxx && 这次花的钱钱 < yyy) {
	这个格子.设置背景颜色(某个颜色);
} else if (...) {
	//...
}

于是我们要做的事情就是,翻文档,看看如何做到上面的事情。

大致阅读文档发现代码有一股 JavaScript 的味道,于是就决定先按 js 的语法套路来写,如果出了问题再查。通过查阅文档可知,获得当前表的方式就是 SpreadsheetApp.getActiveSheet() ,而得到现有表格的数据范围(即这个表的数据情况)则是 getDataRange() 了。当我们对得到的数据取值,只需要 getValues() 即可得到一个映射表,而取得数据范围内某个格子则只需 getCell(行, 列) ,相应的,取得单元格的值使用 getValue() ,为单元格设置背景使用 setBackground("颜色")

于是我们就可以通过这些来实现为每一个现有行的收入支出结果那一列标识不同背景颜色的代码了。我们在 工具 > 代码编辑器 编写代码即可,代码也异常简单,如下所示。

function setDebtColor() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  for (var i = 4; i <= 200; i++) { // index start at 1
    if (i > data.length) break;
    // debt row
    var cell = range.getCell(i, 3);
    var cellValue = cell.getValue();
    if (cellValue - 0 > 0.001) { // incoming
      if (cellValue > 61 && cellValue <= 261) cell.setBackground("#a0c238");
      else if (cellValue > 261) cell.setBackground("#0074bf"); 
      else cell.setBackground("#c4fdb3");
    } else if (cellValue - 0 < -0.001) { // outcoming
      if (cellValue < -61 && cellValue >= -261) cell.setBackground("#de9610");
      else if (cellValue < -261) cell.setBackground("#c93a40"); 
      else cell.setBackground("#fffacd");
    } else {
      cell.setBackground(null);
    }
  }
}

如上我们假设C列的4~200行为需要填色的格子,为支出填红色,收入填绿色(大致..),并根据两个阈值(61和261,别问为啥是这个数)把收入或支出的量的多少分为三段填以不同深浅程度的颜色。填充到最后就完成啦。有意思的是,写这段代码之前我完全不熟悉 Spreadsheet 脚本语言的用法(vba我也不熟悉…),这样竟然没碰到语法错误…

值得一提的是,其一,getCell() 的下标是从 1 开始的,头一次点调试发现内容那一列变色了,当时还觉得挺好看,后来才反应过来不对。另一个是,由于实在懒得去系统的了解这一套脚本语言编写方式之类,故我也没有研究有没有浮点数比较运算的问题,于是对于判断等于0这一点,用了上面写的那种方法。

尾声?

我终于又水了一篇博客,于是对于码农来说,能快速翻阅文档查 API 手册来完成自己想要的任务,应该算是基本素养吧。(写这么一篇博客花的时间是写那一小段脚本的三倍多了吧

更重要的是终于知道我的小钱钱都去哪里了(不对

实际上之前的那份工作,由于本身和我的大学在同一个市里,公司提供住宿,并且也有学长在那里,故和这份新工作相比而言,这份新工作才真的算是让我来到了一个完全陌生的城市吧。坦白说初来这两天,心里的五味瓶翻掉了,也没人可以倾诉,心里憋着实在难受,于是才打算写这么一篇博客换心情。我不知道是不是来到陌生城市的人们最初是不是都会有这种感受,我仿佛完全失去了憧憬未来的能力一般,但我又能做什么呢?房屋租下了,明天就是入职的日子了,这份新工作我寄予了很大的希望在上面,而现在我反而有些惧怕。无论这即将到来的工作带来的是愉快的工作经历还是失望的经历,至少这三个月的生活已经随着租房合同的签订而敲定了。当然,谁不希望一切向着好的方向发展呢?希望一切安好吧。

明天就是新工作入职第一天,水一篇博客,希望一切顺利。

2018年4月1日21点50分