[译]JavaScript:将字符串两边的双引号转换成单引号
原文:http://ariya.ofilabs.com/2012/02/from-double-quotes-to-single-quotes.html
代码的不一致性总是让人发狂,如果每位开发者都能遵守约定好的编码规范(coding conventions),那么生活将变的更加美好.比如在JavaScript中,一个字符串字面量可以用单引号引起,也可以用双引号来引起(ECMAScript 5规范7.8.4小节).很多人习惯于使用某种特定的引号,比如jQuery编码风格推荐人们使用双引号.
但我个人更喜欢使用单引号,这仅仅是我的偏好.自从有了Esprima,我意识到,我可以利用Esprima能够以非破坏式(non-destructive)的方式对输入的JavaScript源码进行局部修改(partial modification)的能力,来强制让输入JavaScript源码中的每个字符串字面量都使用单引号.于是我就写出了下面的singlequote.js脚本:
var fs = require('fs'),
esprima = require('esprima'),
input = process.argv[2],
output = process.argv[3],
offset = 0,
content = fs.readFileSync(input, 'utf-8'),
tokens = esprima.parse(content, { tokens: true, range: true }).tokens;
function convert(literal) {
var result = literal.substring(1, literal.length - 1);
result = result.replace(/'/g, '\'');
return ''' + result + ''';
}
tokens.forEach(function (token) {
var str;
if (token.type === 'String' && token.value[0] !== '\'') {
str = convert(token.value);
content = content.substring(0, offset + token.range[0]) + str +
content.substring(offset + token.range[1] + 1, content.length);
offset += (str.length - token.value.length);
}
});
fs.writeFileSync(output, content);
这个脚本需要用Node.js来执行,像这样:
node singlequote.js inputfile outputfile
该脚本具体是如何工作的?让我们假设输入源码的内容是这样的:
console.log("Hello")
在我们把这句代码传入Esprima解析器的时候,要把其中一个解析选项tokens设为true,这样解析器才会在解析的过程中把遇到的所有token(词法单元)收集到一个数组中,并返回它.对于我们上面的这句代码,返回的token数组看起来是这样的:
[
{ type: "Identifier", value: "console", range: [0, 6] },
{ type: "Punctuator", value: ".", range: [7, 7] },
{ type: "Identifier", value: "log", range: [8, 10] },
{ type: "Punctuator", value: "(", range: [11, 11] },
{ type: "String", value: ""Hello"", range: [12, 18] },
{ type: "Punctuator", value: ")", range: [19, 19] }
]
译者注:在编译原理领域中,token这个词可以被翻译成词法单元或者词法记号,它表示一个在源码中拥有独立意义的最小单位,是不可再分的词法单元(lexical unit).一个token是由若干个字符组成的,就像英文中的单词一样,所以也有人直接把它翻译成单词.在ES标准中,token具体包含有保留字,标识符,字面量,标点符号这几种输入元素(input element).
一旦我们拿到了所有的token对象,剩下的事情就简单多了.我们只需要遍历这个token对象数组,找到那些与某个字符串字面量关联的token(type属性为String的token对象).每个token对象都会在自己的range属性中存放有所关联字符串字面量的位置信息,这是一个表示了所关联字符串字面量在输入源码中的开始位置和结束位置的索引区间数组(闭区间).
{ type: "String", value: ""Hello"", range: [12, 18] }
有了这个位置信息,我们就能使用一些基本的字符串操作来替换输入源码中的某段内容.对于上面这个例子的话,修改目标就是索引位置在[12, 18]之间的源码内容.值得注意的是,如果原始字符串字面量的值(两个引号中间夹着的内容)中包含有一个或多个的单引号,则我们需要做一些额外的工作,就是要把这些单引号进行转义(查看第7.8.4小节的SingleEscapeCharacters).如果真的需要进行这样的转义,则转义后的字符串字面量的长度会大于原始字符串字面量的长度(多了反斜杠字符),从而改变了整个源码的长度,再从而让token数组中其它还未处理的token对象中包含的位置信息产生错位,因此我们还需要进行偏移量的调整.下面是个需要进行转义的字符串字面量的例子:
// 输入源码
"color = 'blue'"; // 不进行转义操作的话会输出非法的字符串字面量
'color = 'blue'';
另外,我写的转换代码还差一件事情没做,就是要把那些不再需要的转义字符也删除掉.也就是原来字符串字面量中包含的双引号前面的那个反斜杠,它已经不再需要了.这项工作就留给读者们实现吧!
译者注:作者说的是这种情况,原字符串字面量为"\"",这时用反斜杠转义里面的双引号是必须的,但按照上面的规则转换之后就成了'\"',虽然这也是一个合法的字符串字面量,且求值结果不变.不过作者的意思是这个反斜杠是多余的,是应该删除掉的.
很显然,我写的这个工具只是为教学演示而用.另外,虽然现在大部分编辑器都支持搜索替换的功能,如果你需要使用编辑器来完成这项任务,也有一定的难度,注意不要替换掉那些不在字符串字面量两边的引号.
译者注:你觉的能用正则表达式来完成这项任务吗?注释和正则字面量中的引号字符会让你束手无策.
你还可以想想看,利用token列表和源码局部修改的技术,还能干哪些事情?
译者注:你有没有发现作者忽略了一个比较极端的情况,就是假如原字符串字面量为"\'",虽然这个反斜杠是多余的,但这的确是一个合法的字符串写法,求值后字符串的值为一个单引号.按照上面的算法转换之后会变成'\\''.显然,这会导致一个语法错误,因为少了一个反斜杠.是不是呢?
有了Esprima,实现这样一个转换器真的是很简单,如下
[译]JavaScript:将字符串两边的双引号转换成单引号的更多相关文章
- JavaScript清除空格、换行,把双引号转换成单引号
1.页面 2.源码 <!DOCTYPE> <html> <head> <meta charset="utf-8"> <titl ...
- Javascript里,想把一个整数转换成字符串,字符串长度为2
Javascript里,想把一个整数转换成字符串,字符串长度为2. 想把一个整数转换成字符串,字符串长度为2,怎么弄?比如 1 => "01"11 => " ...
- Linux c字符串中不可打印字符转换成16进制
本文由 www.169it.com 搜集整理 如果一个C字符串中同时包含可打印和不可打印的字符,如果想将这个字符串写入文件,同时方便打开文件查看或者在控制台中打印出来不会出现乱码,那么可以将字符串中的 ...
- java字符串转义,把<>转换成<>等字符【原】
java字符串转义,把<>转换成<>等字符 使用的是commons-lang3-3.4 中的StringEscapeUtils类 package test; import ja ...
- 坑爹的PostgreSQL的美元符号(有时需要替换成单引号)
今天想在PostgeSQL数据库里建一个存储过程(或函数也行),由于对存储过程比较生疏,上网搜了很多教程和源代码例子,照着写,发现怎么都不行,甚至把网上教程包括官方教程的源代码原封不动的复制下来一执行 ...
- javascript消除字符串两边空格的两种方式,面向对象和函数式编程。python oop在调用时候的优点
主要是javascript中消除字符串空格,比较两种方式的不同 //面向对象,消除字符串两边空格 String.prototype.trim = function() { return this.re ...
- JavaScript去除字符串两边空格trim
去除字符串左右两端的空格,在大部分编程语言中,比如PHP.vbscript里面可以轻松地使用 trim.ltrim 或 rtrim实现.但在js中却没有这3个内置方法,需要手工编写.下面的实现方法是用 ...
- 为什么 JSON 接口的数据都要加双引号!!!不能用单引号
原因是:Javascript 在很多时候会把 JSON 对象里面没有双引号包围的值,当做数值处理.比如: {"a":987654321} 这个 JSON 里头的变量 a,会被当做一 ...
- JSON 的标准:双引号而非单引号!
刚刚测试发现一段很简单的.看似正确的代码却是错误的: <?php $json_str = "{'name':'Eric', 'age':23}"; var_dump(json ...
随机推荐
- CruiseControl.NET与TFS结合的配置文件
配置如下: <cruisecontrol xmlns:cb="urn:ccnet.config.builder"> <project name="测试项 ...
- mplayer依赖关系不满足
mplayer以及其他fork出来的如mplayer2是命令行下的媒体播放器.一般ubuntu等的桌面系统都自带.然而自己使用了一段时间后突然出现缺少库文件,各种依赖关系不满足也未能重新安装.为了以后 ...
- UEditor上传图片到七牛云储存(java)
我们的网站一般放在虚拟空间或者服务器上,图片如果存在本地目录,会占用很多空间和流量,还增加了负担,好的办法是把图片存放到云储存服务里面,平时用url去拿 云储存:普遍说又拍云和七牛比较好,看到七牛免费 ...
- PHPstorm激活
最近想学习一下PHP 于是下载了很不错的phpstorm 但这老外的工具是要购买正版的 所以就搜了一下破解激活的教程 发现现在网上的在线破解在2016.2版本里面大多已被封杀 尝试了本地破解也发现大 ...
- vs 2012 + OPenCV 2.4.8 配置
一:安装Opencv 下载opencv-2.4.8.exe,然后安装在目录D:\opencv-2.4.8. 二:配置vs 2012 1.打开vs创建项目 2.下一步,选择dll ,空项目,然后完成.后 ...
- BZOJ2049: [Sdoi2008]Cave 洞穴勘测 Link-Cut-Tree 模板题
传送门 搞了这么长时间Splay终于可以搞LCT了,等等,什么是LCT? $LCT$就是$Link-Cut-Tree$,是维护动态树的一个很高效的数据结构,每次修改和查询的均摊复杂度为$O(logN) ...
- 网络存储(二)之ISCSI原理
组成 一个简单ISCSI系统大致由以下部分构成 ISCSI Initiator 或者 ISCSI HBA ISCSI Target 以太网交换机 一台或者多台服务器 结构图如下: iscsi服务器用来 ...
- Codeforces Round #345 D. Image Preview(二分)
题目链接 题意:看一个图片需要1单位时间,如果是 w 需要翻转 b 时间,切换到相邻位置(往左或者往右)需要 a 时间,求T时间最多能看几张图片 从第一个开始向右走看若干个图片然后往如果往左走就不会再 ...
- 【原】CSS3 Media在常用设备的设置值
摘要:今天的一个小小的项目中,在各种手机上样式都显示正常,唯独iphone4s的有些许问题.产品经理又说iphone4s用户还挺多的,无奈,只能查一查iphone4s的media值,顺便做个小小总结; ...
- angular 兼容ie7 实现
<script src="~/Content/js/angular.min.js"></script><script src="~/Cont ...