在之前的一个问题中,我被告知谷歌会将UTF-8编码的响应传递给查询。这解决了非破坏空间(A0)在被curl传递到我的终端后被混淆的问题。这是通过将curl输出管道化到inconv并转换为UTF-8来解决的。然而,即使有了这个解决方案,我仍然会得到一些奇怪的输出。
考虑以下2米到英尺的转换:
http://www.google.com/ig/calculator?hl=en&q=2%20m%20in%20英尺
这是我在浏览器和其他地方看到的输出:
{lhs: "2 meters",rhs: "6.56167979 feet (6 feet 6x3csupx3e47x3c/supx3ex26#8260;x3csubx3e64x3c/subx3e inches)",error: "",icc: false}
预期输出为:
{lhs: "2 meters",rhs: "6.56167979 feet (6 feet 6 47/64 inches)",error: "",icc: false}
我可以使用正则表达式或其他解决方案进行文本替换,但我想知道这里发生了什么。有什么见解吗?
我正在运行Mac OS X Mountain Lion 10.8.2
通过curl访问的Google Calculator返回JSON。Google使用\xHH表示法作为JSON的标准。如果输出被发送到浏览器(或任何其他解析HTML的东西)而不是标准输出,那么只需要一个好的JSON解码器。
让我们看看我们可以从命令行中做些什么来解析JSON。
echo -en $(curl -s 'http://www.google.com/ig/calculator?hl=en&q=4^22') > ~/temp.html
这为我们提供了有效的HTML,我们可以通过浏览器查看,但我们需要将所有内容减少到可以通过标准输出显示的内容。
echo -en "$(curl -s --connect-timeout 10 "http://www.google.com/ig/calculator?hl=en&q=2%20m%20in%20feet")" | sed -e 's/<sup>/ &/g' -e :a -e 's/<[^>]*>//g;/</N;//ba' | perl -MHTML::Entities -ne 'print decode_entities($_)' | iconv -f ISO-8859-1 -t UTF-8
对于echo命令,-e解释转义符,如\x3e、\x3c和\x26(分别为<、>和&),而-n则抑制echo通常会添加的换行符。
sed的管道在所有(上标)标记之前添加一个空格,然后删除所有HTML标记。
然后,到perl的管道解码所有HTML实体,例如⁄;至⁄(分数斜线)。http://en.wikipedia.org/wiki/Html_special_characters#Character_entity_references_in_HTML
到iconv的管道将ISO-8859-1输出转换为预期的UTF-8。这是最后完成的,因为perl行可以生成需要正确转换的UTF-8实体。
这仍然会有区分分数和指数的问题(47/64,其中47用上标标记包裹,64用下标标记包裹,10^13,其中13用上标标记包装)。
我们可能会变得非常愚蠢,并制作一条非常长的sed行来解析所有特殊字符(下面是AppleScript中的内容,所以你可以看到语法有多荒谬):
set jsonResponse to do shell script "curl " & queryURL & " | sed -e 's/[†]/,/g' -e 's/\\x26#215;/*/g' -e 's/\\x26#188;/ 1\/4/g' -e 's/\\x26#189;/ 1\/2/g' -e 's/\\x26#190;/ 3\/4/g' -e 's/\\x26#8539;/ 1\/8/g' -e 's/\\x26#8540;/ 3\/8/g' -e 's/\\x26#8541;/ 5\/8/g' -e 's/\\x26#8542;/ 7\/8/g' -e 's/\\x3csup\\x3e\([0-9]*\)\\x3c\/sup\\x3e\\x26#8260;\\x3csub\\x3e\([0-9]*\)\\x3c\/sub\\x3e/ \1\/\2/g' -e 's/\\x3csup\\x3e\([0-9]*\)\\x3c\/sup\\x3e/^\1/' -e 's/( /(/g'"
†(dagger)字符在MacRoman集合(Macintosh编码)中为十进制160。在十六进制中,这是0xA0或\xA0,并以UTF-8编码方式编码到非中断空间,这就是谷歌传递的信息。因此,在AppleScript中,为了取代UTF-8中的非中断空间,由于Macintosh编码,我们不得不使用†(dagger)。
- http://en.wikipedia.org/wiki/Mac_Roman#Codepage_layout
- http://en.wikipedia.org/wiki/UTF-8
- http://en.wikipedia.org/wiki/C1_Controls_and_Latin-1_Supplement
sed行还处理几个特殊的分数符号:http://tlt.its.psu.edu/suggestions/international/bylanguage/mathchart.html#fractions
这个故事的寓意是,在处理JSON时,只需使用一个好的JSON解析器。
一个次要的寓意是:不要使用AppleScript来处理JSON。
问题的公认答案谷歌计算器有官方API吗?是否定的,所以你似乎只需要尝试对其功能进行逆向工程。这里,它似乎表示分数47/64,使得分子47在<sup>
标记内,分母64在<sub>
标记内,然后使用xnn
表示法对<
和>
进行转义,其中nn
是字符的十六进制代码。这似乎没有多大意义,因为风格上的上标和下标毫无意义,在HTML标记中这样做很奇怪,而转义标记分隔符也很奇怪。然而,主要的问题是,有时<sup>
可能意味着用上标使表达式成为指数,因此仅仅删除这些信息可能会扭曲信息。