[译]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 ...
随机推荐
- spoj1811 Longest Common Substring
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- 前端打包/自动化构建工具:fis3
据说这个可以进行打包,并且可以实现类似/script/test-adsf123.js或者/script/test.js?v=asdf123 先做个记号 参考:http://fis.baidu.com/
- Visual Studio多版本进行切换的研究
最近在升级公司内部的项目到最新的开发工具Visual Studio 2015,可能在团队开发上会遇到这些问题: 1.团队成员的电脑和系统,设置安装的开发工具参差不齐 2.有些成员的Visual Stu ...
- PHP扩展编写、PHP扩展调试、VLD源码分析、基于嵌入式Embed SAPI实现opcode查看
catalogue . 编译PHP源码 . 扩展结构.优缺点 . 使用PHP原生扩展框架wizard ext_skel编写扩展 . 编译安装VLD . Debug调试VLD . VLD源码分析 . 嵌 ...
- Android——旋转屏幕导致Activity重建解决方法
Android开发文档上专门有一小节解释这个问题.简单来说,Activity是负责与用户交互的最主要机制,任何“设置”(Configuration)的改变都可能对Activity的界面造成影响,这时系 ...
- IOS - 打印COOKIE中的 CRFSToken
NSHTTPCookie 在iOS中使用NSHTTPCookie类封装一条cookie,通过NSHTTPCookie的方法读取到cookie的通用属性. - (NSUInteger)version; ...
- Linux下串口编制【转】
串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调 ...
- 我的WCF Data Service 系列 (一、为什么要有WCF Data Service)
开篇先说两名题外话, 在博问上,经常看到有个问性能问题,比如Entity Framework的性能行不行啊之类的. 其实这个行不行,关键还是看对象,一夜家族的老七可能勉强吃点蓝片片,也就行了,可真要让 ...
- Django 自带的ORM增删改查
通过Django来对数据库进行增删改查 1 首先创建类,在app应用程序里面的model模块里面创建类,写好数据库信息,方便我们待会初始化: 2 创建在django项目里面的settings里面添加 ...
- JAVA内存机制
Java程序运行时,数据会分区存放,JavaStack(Java栈). heap(堆).method(方法区). 一.JVM内存模型 1.Java栈Java栈的区域很小,只有1M,特点是存取速度很快, ...