## Writing a Comparator for Natural Sort Order

Natural sort order is what we usually see in most file managers when browsing a list of numbered files, that it sorts the numerical part of the file name as a number instead of comparing it character by character. For instance:

Lexicographical sort Natural sort
1.txt 1.txt
10.txt 2.txt
100.txt 3.txt
101.txt 4.txt
102.txt 5.txt
103.txt 10.txt
104.txt 11.txt
105.txt 12.txt
11.txt 13.txt
12.txt 14.txt
13.txt 15.txt
14.txt 100.txt
15.txt 101.txt
2.txt 102.txt
3.txt 103.txt
4.txt 104.txt
5.txt 105.txt

Lexicographical sort can be easily implemented using `String::compareToIgnoreCase`, but it is not very acceptable for end users. However for natural sort, things is actually a little more complicated.

## The Definition

There is a small Wikipedia article on Natural Sort Order, which mentioned the following definition for natural sort order:

Natural sort order is an ordering of strings in alphabetical order, except that multi-digit numbers are ordered as a single character.

However, there’s still some undefined behavior about this sort order when case-insensitivity is involved alongside treating numbers as a whole. In an article discussing natural sort order in C, the author mentioned the following case:

Name
Test1
tesT1
test1
tEst2
test2
test3

These string is listed in a reasonable way, however if you simply define the natural sorting to be sorting chunks of characters and numbers individually, the `Test` string have to be equal to `test` so that the ordering won’t be deterministic.

And there’s another case involving leading zeros:

Name
test1
test01
test001
test01a

Intuitively, things that are shorter should come before those longer ones, so equal numbers with less leading zeros should come before those with more. Furthermore, if there’s more text following the number, it should come after those without, thus the aforementioned leading zero comparison has a lower priority.

I didn’t find any standard for these corner cases, so I’m merely deciding on the most reasonable approach.

## Various Implementations

There’s an article on CodingHorror and a StackOverflow question that referenced some existing implementations.

And here are some additional implementations that I found inside some battlefield applications:

But there’s some common issues in existing implementations:

• Use of regular expression: The comparator is frequently evaluated during the sort, so performance is our concern and splitting on regular expressions is not what we expect under such conditions.
• Memory allocation: Also due to the frequent invocation, we should avoid memory allocation (e.g. actually building those “chunks”), and this can be done by iteration over the two strings.
• Unicode awareness: Unicode code points are not necessarily single `char`s (think of surrogates), so those code point related methods should be used instead of simple increment to advance the index of current “character”.
• Locale awareness: Instead of `c >= '0' && c <= '9'`, one should use `Character.isDigit()` and `Character.digit()` for getting numbers out of a character.
• Correctness: Some implementations cannot handle the two aforementioned corner cases properly.
• Coding style: Some implementations are simply not so readable.

## My Implementation

So I wrote my own implementation with those issues in mind, and it basically iterates over the two string and handles consecutive digits together. Most of the code is self-explanatory and the comments can also describe the algorithm:

## Further Considerations

In fact, to account for Unicode’s compatibility decomposition, canonical composition and case folding, an ICU `Normalizer` should be used with mode `NFKC_Casefold`. However, since the ICU package is not available on Android until Android Oreo, and the JDK implementation didn’t account for such level of correctness, I’m currently leaving it out and you can trivially add it by applying the normalization before comparison.

## Fixing My Missing Degree Celsius Symbol

For years OpenWeather has been my favorite GNOME extension for quick and beautiful weather information. However today when I looked at my top bar again for weather, I had the impression as if something is missing:

And this is what it used to be like:

My degree Celsius symbol is missing!

## Finding the culprit

The first thing I thought was, is this specific to OpenWeather? And I was surprised to find out that when I googled “degree Celsius symbol”, the `°C` as `U+00B0 ° degree sign` plus `U+0043 C latin capital letter c` is present, while ℃ as `U+2103 ℃ degree celsius` is simply empty. However a `<span>` with `font-family: serif` on Wikipedia showed the symbol correctly, so this must be a font/fontconfig issue.

And I `less`ed my own fontconfig configuration with `/etc/fonts/local.conf`:

So the different order of font families in `sans-serif` and `serif` might be the issue. I googled a while for finding out the font selected by `fontconfig` for a glyph, and found an article suggesting the use of `FC_DEBUG` and `pango-view`:

The latter part basically filters out the last printed family name from the tedious debug output. And when I run this for my degree Celsius symbol (`℃`), I found:

What’s wrong with `WenQuanYi Micro Hei`? I’ve been using it for years, and now it’s giving me nothing for degree Celsius symbol? And why did fontconfig ever choose it seemed to have no such glyph?

Confused by this I opened my `wqy-microhei.ttc` with FontForge, and was again surprised to find out that my `WenQuanYi Micro Hei` is providing an empty glyph (instead of nothing) for certain codepoints!

This is crazy, and I’m left wondering how my degree Celsius symbol ever worked in the past few years.

## Finding the way to fix it

There must be some configuration that allow me to blacklist certain glyphs in a font. And after another round of digging around, I found some interesting results.

The first one is a bug on fontconfig Bugzilla which requested such support back in 2006 and was marked fixed in 2011. Feeling excited, I scrolled down and found a single line of comment from the dev:

This is fixed in master with target=scan charset editing.

After all the hard work, why didn’t he or she celebrate the moment of closing this bug with a more detailed explanation, or at least a helpful pointer? Even after reading though `man fonts-conf`, I found nothing describing how I can edit the charset of a font family. After all, the `<charset>` element says it must contain one or more integer, however the whole charset normally contains a huge amount of hexadecimal integers.

So I searched harder and found another answer on StackOverflow. It suggested an undocumented way of configuration that’s mentioned somewhere in a RedHat bug thread, which was its only appearance on the whole Internet:

This is just what i wanted! So I happily applied this to my mischievous `WenQuanYi Micro Hei`, changing the `compare` to `"eq"` and setting the range to include `0x2103` (My precious degree Celsius symbol). Finally, `sudo fc-cache -f && fc-cache -f`! [sigh of relief]

Nope.

This could have worked, in some time of the history, but is not working for now, on my latest Arch Linux installation.

No.

But wait. I did saw something mentioning, we have a `<charset>` element and it must contain some integers? So I started to coin my own solution (You should also do the same for `WenQuanYi Micro Hei Mono`):

`sudo fc-cache -f && fc-cache -f`, `pango-view` again to confirm, and `Alt+F2 r` to restart my GNOME shell. It worked! After all these hours, my degree Celsius symbol is back and alive again!

## A final note

The above solution is only a workaround, and to actually fix this, The `Wenquanyi Micro Hei` font itself should be patched. In fact this was what I first tried when I surprisingly found out those empty glyphs.

However, when I went to wenq.org, there latest update was posted in late 2011 (We are in 2018 now), and their forum is giving me a blank page with certain resources returning 404. Their SourceForge issue tracker is also unattended for years with that notorious hangul advance bug still open. Sadly, the whole project seems dead. So I decided to work around instead of fixing this.

And one sentence I encountered during my search kept lingering in my mind:

When you gaze long into fontconfig, fontconfig also gazes into you.

Update: With another link on their official website, I was able to find their real bug tracker and this bug, and a similar bug. The dev said it’s fixed, but maybe some recent `fontconfig` or `freetype` changes brought it back. Maybe some day I should fork it and try to actually fix these bugs.

And according to the dev’s comment, those glyphs existed in `Droid Sans Fallback`, so a proper fix to my configuration should also include adding `Droid Sans Fallback` to the `sans-serif` and `monospace` families, right below the `WenQuanYi Micro Hei` entry.

## 前言

JavaScript 是一门灵活的动态语言，在实现应用功能时十分易用。最近有写作图形界面程序的需要，又比较喜爱 GTK+ 3 的设计，因此想到可以尝试使用 JavaScript 来完成任务。

## 编写应用程序

GNOME 官方提供了 一个简单的 GJS 程序示例，可以按照它的架构进行编程。

## 技巧

### 通过构造器设置属性

`Gtk.Widget` 的所有属性均可以通过向构造器传入的 `Object` 进行设置，而可用的属性可以通过运行 `gtk3-widget-factory`，然后启用 GtkInspector 来查看和实验。

### 控件杂项

`Gtk.Entry` 相当于 Android 中的 `EditText`。可以通过设置 `width_char` 来修改 `Gtk.Entry` 的最小大小。

`Gtk.Widiget``sensitive` 属性相当于 Android 中的 `android:enabled`

## 结语

Gjs 使得我们可以使用灵活的 JavaScript 编写美观的原生程序，总体来说体验是很好的。

## 构建文档

xeCJK 是提供 LaTeX 中文支持的宏包，并且依赖于 XeLaTeX，因此，我们需要使用 `xelatex` 命令进行构建。

LaTeX 在构建交叉索引时需要多次运行，才能最终解析所有的引用，并且期间需要 BibTeX 对参考文献数据库进行处理。因此，一般的手动构建命令是：

## 了解 LaTeX 和解决问题

LaTeX 有很多历史问题带来的不同，也有多重相似但不同的工具选择，因此网上提供的解决方案不一定可以工作，需要自己试验。

## 零碎知识

• `\`：换行，不新建段落。可选参数可以控制空白长度。
• `par`：创建段落。`parskip``parindent` 将生效。部分命令需要对段落才能生效，因此可能需要在最后一段文字最后加上 `par`
• ：一个空格。
• `&`：一个 NBSP，不会被分行打断，常用于类似 `图~1` 这样的场景。
• `hspace{1em}`：一个 1 em 长度的空格。
• `renewcommand`：修改命令定义。
• `setlength`：修改长度变量。
• `setcounter`：修改计数器。

## 结语

LaTeX 十分强大，并且作为纯文本格式依然比 Word 文档等更加清晰、明确、可靠。但是，整个 LaTeX 环境也正因为它的高自由度和复杂，在许多方面缺乏一致性，这给使用者带来了不少困难。

## 前言

WebGL 拥有与 OpenGL ES 相似的 API（前者基于后者），但与 OpenGL 相比，两者缺少基础图形的渲染管线，而是需要手写 shader 进行渲染。

## String 类

String 类表示一个字符串。 在设计上， 字符串类存储的字符串是不可变的(immutable)。想要修改一个字符串的内容只能通过新建一个新的字符串实例来实现。 且对于两个相同的字符串字面量而言， 他们指向的是同一个字符串对象。

• String类是Java中唯一的具有重载运算符的类。 String重载了+运算符， 使得对于一个加号左右两边的String能够被连接起来。

### 成员变量

String类具有以下的关键成员变量：

`final char[] value`

`final int count`

`final int offset`

### 私有类

`private static final class CaseInsensitiveComparator`

String类私有类， 其具有compare()方法， 用于提供对于字符串之间的大小写不敏感的比较。

### 构造器

`public String ()`

`public String (String str)`

`public String (char[] data)`

`public String (char[] data, int offset, int count)`

`public String (byte[] ascii, int hibyte, int offset, int count)`

`public String (byte[] ascii, int hibyte)`

`public String (byte[] data, int offset, String encoding)`

`public String (StringBuffer buffer)`

`public String (StringBuilder buffer)`

## StringBuffer 类

StringBuffer类表示一个 可变的(changeable) 字符串， 它提供了一系列成员方法来对StringBuffer实例进行修改， 包括`insert`, `replace`, `delete`, `append``reverse`等。

StringBuffer实例是变长的， 所以尽管在定义时， 可能是以固定长度定义的， 但它的长度都可以进行不断正常。

`new StringBuffer().append(str_a).append(str_b).toString()`

### 成员变量

StringBuffer类拥有以下的关键成员变量:

`int count`

`char[] value`

`boolean shared`

### 构造器

`public StringBuffer()`

`public StringBuffer(int capacity)`

`public StringBuffer(String str)`

## StringBuilder类

StringBuilder类表示一个 可变的(changeable) 字符串， 与StringBuffer类似， 它也提供了诸如`insert`,`replace`,`delete`, `append`, `reverse`之类的方法。 但是与StringBuilder不同的是，StringBuilder是不同步的， 只能在一个线程的情况下使用。

### 关键成员函数

`int count`

`char[] value`

### 构造器

`public StringBuilder()`

`public StringBuilder(int capacity)`

`public StringBuilder(String str)`

`public StringBuilder(CharSequence seq)`

## 比较异同

### String与（StringBuffer及StringBuilder）进行比较

1. 都表示了一个字符串序列
2. 都是final类， 都不允许被继承
3. 这个字符串序列都是支持Unicode的
4. 都支持对于字符串序列内容的部分读取
5. 都重载了加号运算符， 能够直接使用”+”来连接两个字符串

1. String类型的字符串是 不可变（immutable） 的， 即一个String实例在被创建之后， 其字符串的大小， 内容不能再被改变。 如果需要进行改变的话， 实际上是新建了一个String实例。
2. 而对于StringBuffer和StringBuilder而言， 其本质上实现了一个变长数组(VLA)，所以其字符串大小，内容都是可以进行变化的。在进行修改的时候， StringBuffer和StringBuilder各自实现了一个`public void ensureCapacity(int minimumCapacity)`的方法， 以确保时刻Buffer数组的大小要大于`minimumCapacity`, 否则就将数组扩充成其原来size的两倍再加二。
3. String类型对于字符串本身的操作更多，诸如`toLowerCase`, `toUpperCase`这类大小写转换的方法， 以及`matches`, `split`,`replace`这类正则表达式方法， 以及`trim``concat`这类操作字符串的方法，都仅在String类中实现，而在StringBuffer与StringBuilder类中并没有提供以上接口。

### StringBuffer 与 StringBuilder进行比较

1. 前面与String类型共有的相同点不赘述
2. StringBuffer类与StringBuilder类都实现了一个 可变的(changeable) 字符串对象， 可以通过一系列方法对字符串内容进行诸如增加，删减，插入，替换，翻转等操作。
3. 实现的字符串buffer的本质都是一个变长数组(VLA)， 在任何时刻都尽量保证数组不越界， 如果接近了其边界， 就将数组的大小扩充成原来大小的两倍加二。
4. 默认的buffer大小`DEFAULT_CAPACITY`都为16

1. StringBuilder类相较StringBuffer, 多了一个基于CharSequence建立的构造器。
2. StringBuffer比StringBuilder类多了一个`shared`指示，以标记buffer内容是否被多个对象所引用。如果被多个引用的话，在进行操作的时候就要将这个buffer再复制一份， 以保证其单引用的性质。 这一点其实是为了保证操作内容的同步化进行的。
3. 正如之前所说， StringBuffer和StringBuilder的最大不同点在于其操作的同步性。 StringBuffer在其大多数成员方法前都加上了`synchronized`关键字， 以保证其线程安全。 也就是说， 在同一时间， 只有一个线程能够对同一个StringBuffer对象进行操作，这种限制避免了线程之间读写的冲突。 而对于StringBuilder来说， 就没有这一层限制。故其有可能会引起线程之间的冲突， 但从另一个角度而言， 也减少了诸如线程锁之类的可能的系统开销。 故相比StringBuffer而言， StringBuilder的速度可能会更快一些。 故两者需要权衡使用。

## 前言

Reveal.js 是一个美观实用 HTML 演示文稿框架，只需要你决定内容，就可以方便地产出外观优雅的演示文稿。你可以在线查看 Reveal.js 的 Demo

## 基本

• `404.html`：GitHub Pages 将使用此页面作为默认 404 页面的替代，一般可以换成一个符合自己站点风格的页面。
• `CNAME`：对于绑定自定义域名的 GitHub Pages，可以使用这个文件指定自己的自定义域名。
• `.nojekyll`：我们的站点不需要 Jekyll 的特性干预，因此将它关闭来避免可能的问题。

## 结语

Reveal.js 是一个易用而优雅的 HTML 演示文稿框架，借助于它，我已经多年没有用过 PowerPoint 了。至于利用 GitHub Pages 将它放置在网页端，则可以在免运维的情况下可靠地分享自己的演示文稿，同时也可以不用安装大量 `npm` 依赖来开启演讲者视图，算是一个简单又有用的小技巧。

## 前言

Travis CI 是 GitHub 上开源项目采用持续集成的常见选择。为了给 豆芽 提供持续集成版本用于公开测试，我配置了 Travis CI，并自己编写了脚本将构建结果发布到另一个空项目的 Release 中，并将其间的过程和遇到的问题记录于此。

Travis CI 构建 Android 项目的时间较长，因此调试配置时十分耗时。希望我的经验能对他人有所帮助。

## Travis CI

Travis CI 分为免费版（travis-ci.org）和付费版（travis-ci.com），两者之间没有相互的链接或说明，第一次配置时容易混淆。开源项目选择免费版即可。配置过程可以参考官方的 Getting StartedAndroid 项目配置

1. 为了能够找到并下载最新的 Build Tools，需要启用最新版本的 Tools（`- tools`）。
2. Lint 过程中如果 Platform Tools 版本低于 SDK 版本则会报错，需要启用最新版本的 Platform Tools（`-platform-tools`）。
3. 为了能够找到并下载最新的 Platform Tools，需要已有最新的 Tools，因此与官方给出的样例不同，需要将 `- tools` 放置在 `- platform-tools` 之前。

## 上传至 Release

GitHub 提供了在 Release 中上传二进制构建输出的功能。然而，如果直接在项目仓库中为每次 commit 添加 Release（和相应的 tag）则未免过于杂乱，因此我选择了新建 一个只有 README 的仓库，并将所有持续集成版本的 Release 创建在此仓库中。

## 创造一个简单的表单

• 上面的这个模板给每一个选项显示了一个单选按钮。 每一个单选按钮的值与每一个选项的`id`相联系。 每一个单选按钮的名字都是`choice`. 这意味着， 当某人选择了这些单选按钮之一然后提交这个页面的时候， 系统会使用POST传递一个数据`choice=#`, 此处的`#`，代表选中选项的id。 这是HTML表单的基本概念。

• 我们把这个表单的动作属性设置为`{ %url 'polls:vote' question.id% }`， 然后我们设置动作方法为`post`。 此处使用`method='post'`（与之相对的是`method='get'`）十分重要， 因为此处提交表单的这个动作将会出发服务器端的数据操作。 只要当你创建一个需要服务器端数据操作的表单的时候， 使用`post`总是最佳选择。 这个建议并不仅仅真对于Django， 这是Web开发的实际经验。

• `forloop.counter`记录了`for`标签内循环的次数。

• 既然我们创建了一个`POST`表单（拥有着操作数据的功能），我们就需要担心一下跨站请求伪造(Cross Site Request Forgeries)的问题。 但是谢天谢地，你并不需要太过于担心这个， 因为Django创造了一个非常易用的系统来避免这个问题。 简而言之， 所有使用`POST`提交，并且目标是一个内链URL的表单， 都需要有一个`{ % CSRF token % }`标签。

``````url(r'^(?P<question_id>d+)/vote/\$', views.vote, name='vote')
``````

• `request.POST`是一个字典型对象。 它允许你通过键值对来访问POST传递的数据。 在上文的代码中， `request.POST['choice']`以字符串的形式，返回了选中的选项的ID。 `request.POST`的值总是以字符串表示的。

Django同样提供`request.GET`来以同样的方式访问`GET`数据。 在我们的代码中，我们只使用`request.POST`， 来确保数据只由`POST`请求来操作。

• `choice`没有提供一个POST数据的话，`request.POST['choice']`会引发一个`KeyError`错误。 上面的代码检查了`KeyError`错误发生的可能性， 并在choice没有提供POST数据的时候重新显示表单页面，并且返回一个错误信息。
• 在添加了投票统计之后， 代码返回了一个`HttpResponseRedirect`而非一个普通的`HttpResponse``HttpResponseRedirect`只需要一个参数： 被重定向的目标URL。

正如代码中的注释提到的那样， 你应当总是返回一个`HttpResponseRedirect`， 这不仅仅是对于Django而言。 这是一个优秀的编程实践经验。

• 我们在本例的`HttpResponseRedirect`构造器中使用了一个`reverse()`函数。 这个函数帮助我们避免了在视图函数中硬编码写入一个URL。 给定我们想要传递到的那个视图的名字与这个URL模式所需的参数，在这个例子中， 使用我们在第三章教程中创建的URL设置， 这个`reverse()`函数会返回如下字符串：

``````'/polls/3/results/'
``````

这里的3是`p.id`的值。 这个重定向的URL会调用`result`视图来显示最终的页面。

## 使用基础视图： 代码越少越好

• 改变URL设置
• 删除一些旧的，不需要的视图
• 引入基于基础视图系统的新的视图

### 修改视图

• 每一个抽象视图都需要直到它所作用的数据模型。 这个信息由`model`属性传递
• `DetailView`基础视图需要由URL中匹配得到被称为`pk`的主键键值， 所以我们在URL设置中把`question_id`改名作`pk`

## 思想

• 博客主页， 显示最新的几篇博文
• 博文的“详细” 页面， 完整展示某一篇博文的详细信息
• 以年为基础的分类页面 ，以某一年的月份为基础分类博文
• 以月为基础的分类页面， 以某一月的日子为基础分类博文
• 以日为基础的分类界面， 显示某一天发布的所有博文
• 评论动作， 处理对某一篇博文的评论功能

• 问题“索引”视图： 显示最新的几个问题
• 问题“详细”视图： 显示一个问题的文本， 以及一个投票的表单
• 问题“结果”视图： 显示一个特定问题的投票结果
• 投票动作： 处理对某个特定问题的特定选项的投票操作

## 编写你的第一个视图

`polls/urls.py`文件中应当包含如下内容：

url函数传递四个参数， 两个是必须参数： `regex`正则表达式 和 `view`视图。 以及两个可选参数： `kwargs`关键字参数,`name`名称。

## 编写更多的视图

`include()`函数背后的思想是把URL变得“即插即用”。 在这里我们的民调应用是被放在`polls/urls.py`， 他们还可以被放在polls/下， 或者在/fun_polls/下， 或者在/content/polls/下， 他们还可以被放在其它目录下， 而这个应用仍然可以工作。

• Django会找到与这个URL匹配的正则表达式`^polls/`
• 然后Django会截去匹配的字符串`polls/`， 然后把剩下的文本`34/`传递到`polls.urls`URL设置中， 来做进一步操作。
• 此时这个字符串与`r'^(?P<question_id>d+)/\$'`相匹配， 最终映射到一个对`detail()`函数的调用上：

``````detail(request = <HttpRequest object>, question_id='34')
``````

``````(r'^polls/latest.html\$','polls.views.index'),
``````

## 写真正能够做一些事的视图

Django的`TEMPLATE_LOADERS`设置包含了一个指示从不同的源头调用模板的列表。 其中的一个默认选项是`django.template.loaders.app_directories.Loader`， 它自动在每一个`INSTALLED_APPS`中寻找一个’templates’文件夹。 这就是在第二章教程的时候，在我们没有修改 `TEMPLATE_DIRS`的情况下Django依然能够找到模板的原因。

### 一个快捷表示: `render()`

`render()`方法把request对象作为第一参数， 然后把模板名字作为第二参数， 然后一个可选的字典变量作为第三参数。 它返回一个给定的模板通过给定的内容渲染之后得到的HttpResponse对象。

## 删去在模板中硬编码的URL

``````<li><a href="/polls/{ {question.id} }/">{ {question.question_text} }</a></li>
``````

``````<li><a href = "{ % url 'detail' question.id % }">{ { question.question_text } }</a></li>
``````

``````url(r'^(?P<question_id>d+)/\$', views.detail, name='detail'),
``````

## 为URL名称确定命名空间

``````<li><a href = "{ % url 'detail' question.id % }">{ { question.question_text } }</a></li>
``````

``````<li><a href = "{ % url 'polls:detail' question.id % }">{ { question.question_text } }</a></li>
``````