这篇文章发布于 2019年01月20日,星期日,13:17,归类于 JS实例。 阅读 22669 次, 今日 4 次 15 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8402
本文可全文转载,个人网站无需授权,只要保留原作者、出处以及文中链接即可,任何网站均可摘要聚合,商用请联系授权。
一、题目
就是写一个检验方法,输出不符合排版规则的内容。
翻译规则地址:译文排版规则指南
补充细节:
- 数字与单位之间需要增加空格只需要考虑后面是大写字母的场景,因为代码中经常会有类似20px这样的处理,中间不能有空格。
- 标点不能重复专指中文标点,英文标点不考虑,在程序代码中标点重复很常见。
对于字符内容的格式验证,自然就是正则表达式了,因此,本期的题目主要目的之一是学习正则表达式。
正则表达式规则在所有的语言中都是通用的,除了细节上上有些差异,需要的是一模一样的,所以学会了JS中的正则表达式,其他开发语言也可以受用,包括CSS这么语言(CSS中也有正则表达式)。
JS这么语言要想基础扎实,正则表达式一定要好好学习,学到滴水不漏,可以极大提升处理自己的开发效率。包括在其他一些场合解放生产力,比方说Sublime Text这种编辑器在替换的时候是支持正则表达式的,如果你会正则表达式,则简单几个字符就能完成复杂替换,而且绝不会遗漏。那种解放生产力的感觉,会让你觉得,会代码真的好棒,好high!感觉人生已经达到了高潮。
二、几个验证的实现
CSS题目收到近50份回答,这次的正则小测,只有4个实现,人虽少,但都是精英。
其中第一位@XboxYan的回答几乎直接大结局,我就以这个人回答作为案例讲讲正则表达式相关的一些东西。
1. 中英文之间需要增加空格
/([\u4e00-\u9fa5]+[A-Za-z]+|[A-Za-z]+[\u4e00-\u9fa5]+)/g
JS中正则表达式书写有两种方式,一种是直接两个斜杠,还有一种是使用RegExp对象构建。
上面这个例子啊,就是使用的斜杠。
举个最简单的例子,/1/
可以匹配字符串里面是否有字符'1'
。
我们分解下这个正则表达式:
[\u4e00-\u9fa5]
表示中文字符匹配;[A-Za-z]
表示全部的英文字母。于是这个正则表达式可以理解为:
/(中文+英文+|英文+中文+)/g
是不是要更好理解了,剩下的一些符合是什么意思呢?
括号()
表示分组,这里可以去掉,浪费,白白占用匹配资源,直接下面这样既可:
/中文+英文+|英文+中文+/g
这里的竖着的管道符|
在正则表达式中表示或者的意思,也就是匹配中文后面直接跟着英文,或者英文后面直接带着中文这两个场景。
加号+
表示数量,表示1个或多个。正则表达式中还有其他一些表示数量的方法,例如:
- 加号
+
表示1个或多个。 - 问号
?
表示1个或0个。 - 星号
*
表示任意数量。 - 花括号
{}
可以指定数量,例如{2}
表示2个,{2, 6}
表示2-6个,{2,}
表示2个或2个以上。
在本例中,加号也是可以去掉的,不影响匹配。因此,此正则可以进一步简化:
/中文英文|英文中文/g
也就是:
/[\u4e00-\u9fa5][A-Za-z]|[A-Za-z][\u4e00-\u9fa5][A-Za-z]?/g
斜杠后面的g
表示全局匹配,除了g
,还有i
和m
。其中i
表示不区分大小写,m
表示支持多行匹配。
因此,这里的正则可以进一步简化:
/[\u4e00-\u9fa5][a-z]|[a-z][\u4e00-\u9fa5]/gi
2. 中文与数字之间需要增加空格
/([\u4e00-\u9fa5]+\d+|\d+[\u4e00-\u9fa5]+)/g
和第一个验证,中文和英文之间加空格类似,括号和加号都可以简化掉:
/[\u4e00-\u9fa5]\d|\d[\u4e00-\u9fa5]/g
然后这里有个\d
,表示的是匹配数字0-9
,这里的正则也可以写成下面这样:
/[\u4e00-\u9fa5][0-9]|[0-9][\u4e00-\u9fa5]/g
正则表达式中有很多指代专属类别字符的写法,例如:
\d
表示的是匹配数字;换成大写的\D
则表示匹配数字以外其他字符,等同于[^0-9]
。我们如果想要匹配任意字符,可以使用[\d\D]
这种写法。\w
表示匹配数字、字母和下划线;\W
表示匹配数字、字母和下划线以为的其他字符。\s
表示匹配空格、制表符和换行符;换成大写的\S
则表示除了以外空格、制表符和换行符其他字符。\n
表示换行。
3. 数字与单位之间需要增加空格
/\d[A-Za-z]+/g
题目这个需求是不合理的,有些数字和单位之间是不能加空格的,有趣技术文章翻译,必定包含大量的代码,例如10px
等,显然不能加空格。因此,可以认为数字和大写字母之间需要空格。
因此,正则可以调整为:
/\d[A-Z]+/g
4. 全角标点与其他字符之间不加空格
/([\s\S]{2}[\!|\·|\【|\】|\「|\」|\;|\:|\“|\”|\,|\《|\。|\》|\、|\?]\s+)|[\s+(\!|\·|\【|\】|\「|\」|\;|\:|\“|\”|\,|\《|\。|\》|\、|\?)[\s\S]{2}]/g
这个就相当长了,很多人看了会觉得是天书一样,其实很简单,也有不少优化和改进空间。
首先,前后的[\s\S]{2}
是多余的,可以删掉,没有必要再额外匹配任意两个字符;
然后,最外面的分组括号()
也是多余的;
最后,全角符号在正则表达式中是没有必要使用反斜杠\
进行转义的,因此\【|\】|\「|\」|\;|\:
可以写作【|】|「|」|;|:
,这样阅读更方便些。
当前,这里最好的表示方法还是使用RegExp对象,可以大大简化我们的正则表达式,同时更利于维护。如下:
// 全角标点字符们 var strPunct = '!()【】『』「」《》“”‘’;:,。?、'; // 使用管道符连接 var regPunct = strPunct.split('').join('|'); // 此时的正则表达式 new RegExp('['+ regPunct +'] +| +['+ regPunct +']', 'g');
对吧,是不是简单也易读多了。
其中,空格我直接用的普通空格字符进行匹配的,而不是\s
,因为,我不想把换行符也过滤掉。
当我们的正则表达式内容包含变量的时候,可以借助new RegExp()
来实现。
5. 不重复使用标点符号
这里的标点指中文标点,因为英文标点不重复,有些不切实际,例如空字符串''
,就是合法的重复标点。
原本的实现:
/(\~|\`|\!|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?|\!|\·|\【|\】\「\」|\;|\:|\“|\”|\,|\《|\。|\》|\、|\?)\1+/g
洋洋洒洒好长,我们可以简化下:
new RegExp(`(${regPunct})\\1+`, 'g')
就是不使用重复中文标点了。其中,这里的\1
有必要好好说下。
\1
表示捕获匹配,表示捕获第一个分组括号中匹配的值,你可以理解为代称。在正则表达式中,每一个分组括号()
都自带一个看不见的序号,从前往后依次是分组一,分组二,分组三……
这里的\1
就表示匹配的第一个标点,后面跟了个+
则表示,这里重复标点2个或多个都匹配。
捕获分组不仅存在于正则表达式中,当我们使用replace
方法进行正则替换的时候,也存在与替换方法中,使用美元符号$
外加数字表示,例如前后空格过滤trim()
方法的简易polyfill:
if (!''.trim) {
String.prototype.trim = function () {
// $1表示第一个()中匹配的值
return this.replace(/^\s*(.*?)\s*$/, '$1');
};
}
其中'$1'
并不是替换成字符串$1
意思,而是替换成第一个()
中匹配的值,在这里表示首尾空格以外的值。
如果我们需要对捕获分组内容进行额外处理,可以把第二个参数作为function
处理,例如:
this.replace(/^\s*(.*?)\s*$/, function (matches, $1) {
// matches表示完整匹配内容(包括前后空格)
// $1则表示第一个()中匹配的值
// 此时就可以对$1进行处理,返回我们需要的值
})
6. 破折号前后需要增加一个空格
这个超easy:
/(\S(——)|(——)\S)/g
这里几个括号都是多余的,直接下面这样既可:
/\S——|——\S/g
7. 使用全角中文标点
/([^A-Za-z][\~|\`|\!|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?][^A-Za-z])/g
实际匹配要比这个复杂,因为这个和最后一个应为整句需要使用半角标点大量冲突。所以这里规则要细化,前后至少需要出现中文,半角标点才转换为全角,否则认为是英文整句,不处理,保持忽略。
于是,我经过修改变成下面这样:
var strPunctHalf = '!()[]"\';:,.?'; // 不同于全角字符,半角字符需要加转义 var regPunctHalf = strPunctHalf.split('').join('|\\'); // 此时的正则表达式 new RegExp(`[\u4e00-\u9fa5][a-z]*( *[${regPunctHalf}] *)|( *[${regPunctHalf}] *)[a-z]*[\u4e00-\u9fa5]`, 'gi');
8. 数字使用半角
也就是需要匹配10个全角数字,松松的,没什么好说。
/[\uFF10-\uFF19]+/g
9. 遇到完整的英文整句,其內容使用半角标点
/(\「[A-Za-z\s\~|\`|\!|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]*[\!|\·|\;|\:|\“|\”|\,\。|\、|\?][^\」]*\」)|(\《[A-Za-z\s\~|\`|\!|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]*[\!|\·|\;|\:|\“|\”|\,\。|\、|\?][^\》]*\》)/g
完整的英文整句的重要特征是单词与空格,考虑到标点之后可能会有空格,于是,优化了下:
new RegExp(`([a-z]+[${regPunct}|\\s])+[a-z]*([${regPunct}|\\s][a-z]+)+`, 'gi')
足以现在满足大多数的场景。
三、在线验证工具出炉
现在我们有了基础技术,但还不足以作为工具,作为产品让更多人使用,因为在控制台输出这种事情非程序员以外的人是做不来的。
所以,可以将其变成可视化工具。
最后一个回答者@wingmeng参照了 @XboxYan 的一些思路除了输出验证结果,还输出了处理后的正确排版。
于是,站在这两位的肩膀上,我熬夜搞出了一个“翻译内容格式检验工具” —— check.html
直接输入内容,就可以高亮标记错误的翻译排版,同时显示正确的结果。
可以大大减轻校对时候的工作量,如果你也有参加掘金的翻译计划,或者自己平时翻译文章什么的,这个小工具可以试一试,虽不能100%完美解决各种排版问题,但至少可以解决大部分的问题,非常划算。
四、正则很烂也能实现的傻白甜方法
回到题目之外,在实际项目中遇到这样的排版验证需求,本质上就是用工程化的手段让普通人也能发现一些翻译排版的问题,因此,实际上,就算你正则表达式非常的烂,甚至一点也不会,你也能弄出一个可以使用的工具来解放生产力。
首先通过交互设计手段来降低我们实现的成本:
- 我们没有必要一次性所有的规则一次性匹配,我可以让用户选择具体哪条规则,到时候一个一个规则匹配就好了,用户完全不care的;
- 没有必要匹配所有的排版规则,比方说最后单词英文后面是全角标点,整句英文还使用半角标点,有些难度,也有些蛋疼,我们大不了忽略。因为本来就是辅助工具,没必要面面俱到。
然后,判断什么类型的字符,可以不用走高大上、学习成本较高的正则表达式,可以试试基于charCode值判断,例如:
// 判断字符类型
String.prototype.kind = function () {
if (strPunct.indexOf(this) != -1) {
return 'punct';
}
var code = this.charCodeAt(0);
if (code >= 65296 && code <= 65305) {
return 'num-full';
}
if (code > 256) {
return 'zh';
}
if (code >= 48 && code <= 57) {
return 'num';
} else if (code >= 65 && code <= 90) {
return 'en-up';
} else if (code >= 97 && code <= 133) {
return 'en-low';
}
return 'unknown';
};
这个要好理解的多,不同类型的字符串是有着特定的charCode区间范围的。
接下来事件就很简单了,我们只要遍历需要检测的文本内容,判断一下当前字符和下一个字符是否不符合要求就可以了。比方说“中英文之间需要增加空格”,遍历的时候,如果当前字符是中文,同时上一个字符和或者下一个字母是英文,则返回并高亮标记。
验证就结束了,一个循环+字符判断,就算只学习一个月的JavaScript也能够实现,这就是“傻白甜”实现方式。
眼见为实,为了方便大家学习,我专门做了个demo页面:check-foo.html
例如,我点击第一个检查按钮,成功高亮的不合要求的排版内容:
就一个循环外加一大堆if语句,一丁点正则表达式都没实现,就实现了看上去很难的翻译排版校验工具,而且多半比正则实现更稳健。
页面源码可以直接在这个项目的docs目录中找到:https://github.com/zhangxinxu/quiz
五、升职加薪与技术强弱没有直接关系
接下来要引出本次直播答疑最有价值的一个议题,是有关职业发展的,那就是升职加薪与技术强弱没有直接关系。
很多人都有这样一个错误的认识,因为自己的技术越强,薪资就越高,职位就越高,实际上不是这样子的,并没有直接的关系。职位的高低是与你对团队,对公司产生的价值相呼应的。作为一个技术人员,就算你的技术能力并不是非常的强,也能产生非常高的价值,关键在于认知与意识。
举个例子,某公司某团队打算加入掘金的翻译计划,来提高团队的影响力。
其中有个很重要的环节,那就是校验,而校验这种工作往往都是团队的负责人来做这个事情,负责最后的把关,免得出现一些意外的风险。这就问题来了,通常团队的负责人都是很忙的,要靠肉眼去识别那些翻译中出现的小错误,那是非常费心费力费神费时的事情,久而久之,体验会变得非常糟糕。
这个的团队里面有两个前端,一个技术非常扎实,正则玩得666,但总是沉浸在自己的技术世界里,专注于手头上的事情,以自己代码质量世界第一为自豪。另外一个技术一般般,正则玩得233,但是,其敏锐发现翻译排版校验走人工是非常低效的一件事情,于是当机立断决定做了一个工具,可以帮助大家快速的发现一些排版上的问题,解放生产力。虽然技术一般般,但他活用自己已经掌握的一些知识,通过良好的交互设计降低实现成本,用“傻白甜”的方式把这个东西给做出来了,别人一用,嘿,还行。
很显然,这件事情上,那个技术一般般的人创造的价值更大,而且大的非常明显。一个人技术再强,那解放只是你一个人的生产力,团队还有其他好几十号人并没有任何提升;但是如果你做出一个可以让大家都能提高生产力的工具,就算你技术一般般,但是你对这个团队产生的价值是非常深远的。翻译这种事情,全国有那么多人参加,如果你把这个工具开源出去,对团队带来的影响力要远比翻译一两个文章更高。
对比下:技术强的人自己生产力很高,然后没有然后;技术一般般的人让团队其他人生产力提高,同时通过开源工具给团队带来了影响力。如果你是领导,如果你是boss,你会提拔哪一个人?显然,只要领导不是智障,都会升职加薪是后面那个技术一般的人!
很多技术人员一直没有意识到这个问题,经常会抱怨,那个人技术那么烂,为什么这次升职晋升的是他?拜托,升职晋升是看贡献,不是看你一个人的技术水平,这个和搞科研是不一样的,企业是商业机构。
所以,大家一定要扭转意识,敏锐捕捉可以产生巨大价值的场景,不要只盯着自己的一亩三分地。工作中所有同事遇到的不爽、不悦,所有那些重复人力的场合,都是一次很好的提高你绩效的机会,就算你技术一般般,也能产生非常大的价值;如果你本身技术就很强,那更要抓住这样的机会,否则机会留给了别人,最后怎么被踩下去都不知道,那更惨!
六、关于本次直播
本次直播有录播,因为加班错过的小伙伴可以去围观,地址是:https://www.bilibili.com/video/av41104858/
欢迎提出各种意见。
关于群小测
每周三下班后会在微信粉丝群公布一道小测题,每周六上午10:00-11:00会以直播形式对大家的解答进行答疑。
目前一群已满,二群还有坑我,想入的可以加我微信好友 zhangxinxu-job,我拉你们进去,备注“入群”,然后附上你们的姓名,方便我备注。
好,本次答疑文字版就到这里。
我要看刀剑去了。
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=8402
(本篇完)
- JavaScript实现http地址自动检测并添加URL链接 (0.337)
- 翻编-JavaScript有关的10个怪癖和秘密 (0.337)
- 粉丝群第1期CSS小测点评与答疑 (0.329)
- DOM基础小测27期答疑文字版-窗体滚动二三事 (0.329)
- DOM小测28期 - DOM节点文档前后位置判断 (0.329)
- 纯客户端页面关键字搜索高亮jQuery插件 (0.320)
- JS replaceAll 和 matchAll 使用指南不指北 (0.320)
- jQuery-很酷的弹出层效果js插件 (0.205)
- jQuery之replace字符串替换实现不同尺寸图片切换 (0.205)
- CSS按钮(a/button)生命周期的一些认识 (0.188)
- Selectivizr-让IE6~8支持CSS3伪类和属性选择器 (RANDOM - 0.017)
发现一个问题,中英文的匹配,
英文+单个中文+英文这种格式没法一次性没筛出来 。得多次筛,例如 “OO凸OO”
其他的也是一样有这种情况,有方法可以避免吗
\W表示匹配数字、字母和下划线以为的其他字符。这里的“以为”应该改成“以外”
个人感觉关于晋升那块感觉格局略小,如果公司发挥不出技术达人的能力,那是公司的问题,公司的损失。技术岗高级职位的晋升还是需要技术作为主要衡量标准。
技术233的人费了九牛二虎之力写了一个233的工具,被技术666的人半小时写了个更好的,你说领导用哪个???
关键要写呀,很多技术666的人压根不写呀~
觉得大佬说话有点娘啊,哈哈哈
怎么从第一期突然就到27期了…
加入阅文可得前26期。
怎么加入阅文呢
[]里为什么要加|?直接[【】。,]就好了,不要或符
> 五、升职加薪与技术强弱没有直接关系
赞~从实际中来,到实际中去。
格式检验工具和demo都打不开啦~~~
多试试,托管在github上的,可能偶尔会抽。
?最后一条,我是看了规则里面的示例, 理解成了必须要类似于带《》「」这样的语句才是英文特殊语句。。