[译]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 ...
随机推荐
- bzoj1103: [POI2007]大都市meg
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1103 题目大意:在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Ma ...
- PowerDesigner设计表时显示注释选项
选定编辑的表,[右键]->[Properties]->[Columns]->[Customize Columns and Filter]->[Comment]->[OK] ...
- Linux Crontab 定时任务 命令详解
一. Crontab 介绍 crontab命令的功能是在一定的时间间隔调度一些命令的执行. 1.1 /etc/crontab 文件 在/etc目录下有一个crontab文件,这里存放有系统运行的一些调 ...
- hdu–2369 Bone Collector II(01背包变形题)
题意:求解01背包价值的第K优解. 分析: 基本思想是将每个状态都表示成有序队列,将状态转移方程中的max/min转化成有序队列的合并. 首先看01背包求最优解的状态转移方程:\[dp\left[ j ...
- primefaces 通过selectOneMenu更新显示隐藏区域
最重要的是update的区域要指定整个panel,而不是想更新的那个组件 <h:form id="frm"> <h:panelGrid id="pane ...
- auto dock
http://mgltools.scripps.edu/ http://mgltools.scripps.edu/downloads/previous-releases/mgltools-1-5.4/ ...
- netty 解决TCP粘包与拆包问题(一)
1.什么是TCP粘包与拆包 首先TCP是一个"流"协议,犹如河中水一样连成一片,没有严格的分界线.当我们在发送数据的时候就会出现多发送与少发送问题,也就是TCP粘包与拆包.得不到我 ...
- windows系统下安装MySQL
可以运行在本地windows版本的MySQL数据库程 序自从3.21版以后已经可以从MySQL AB公司获得,而且 MYSQL每日的下载百分比非常大.这部分描述在windows上安装MySQL的过程. ...
- 利用百度开发者中心的api实现地图及周边的搜索
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- TP中验证码的实现