20

粉丝群第27期JS基础小测答疑文字版

 5 years ago
source link: https://www.zhangxinxu.com/wordpress/2019/01/js-quiz-27/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

byzhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8402

本文可全文转载,个人网站无需授权,只要保留原作者、出处以及文中链接即可,任何网站均可摘要聚合,商用请联系授权。

Bni63mQ.jpg!web

一、题目

Z7fmM37.jpg!web

就是写一个检验方法,输出不符合排版规则的内容。

翻译规则地址: 译文排版规则指南

补充细节:

  1. 数字与单位之间需要增加空格只需要考虑后面是大写字母的场景,因为代码中经常会有类似20px这样的处理,中间不能有空格。
  2. 标点不能重复专指中文标点,英文标点不考虑,在程序代码中标点重复很常见。

对于字符内容的格式验证,自然就是正则表达式了,因此,本期的题目主要目的之一是学习正则表达式。

正则表达式规则在所有的语言中都是通用的,除了细节上上有些差异,需要的是一模一样的,所以学会了JS中的正则表达式,其他开发语言也可以受用,包括CSS这么语言(CSS中也有正则表达式)。

JS这么语言要想基础扎实,正则表达式一定要好好学习,学到滴水不漏,可以极大提升处理自己的开发效率。包括在其他一些场合解放生产力,比方说Sublime Text这种编辑器在替换的时候是支持正则表达式的,如果你会正则表达式,则简单几个字符就能完成复杂替换,而且绝不会遗漏。那种解放生产力的感觉,会让你觉得,会代码真的好棒,好high!感觉人生已经达到了高潮。

二、几个验证的实现

CSS题目收到近50份回答,这次的 正则小测 ,只有4个实现,人虽少,但都是精英。

其中第一位 @XboxYan 的回答几乎直接大结局,我就以这个人回答作为案例讲讲正则表达式相关的一些东西。

6fiIVnN.png!web

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]/g

斜杠后面的 g 表示全局匹配,除了 g ,还有 im 。其中 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 的一些思路除了输出验证结果,还输出了处理后的正确排版。

VNjuI36.png!web

于是,站在这两位的肩膀上,我熬夜搞出了一个“翻译内容格式检验工具” —— check.html

直接输入内容,就可以高亮标记错误的翻译排版,同时显示正确的结果。

uUbqQnJ.png!web

可以大大减轻校对时候的工作量,如果你也有参加掘金的翻译计划,或者自己平时翻译文章什么的,这个小工具可以试一试,虽不能100%完美解决各种排版问题,但至少可以解决大部分的问题,非常划算。

四、正则很烂也能实现的傻白甜方法

回到题目之外,在实际项目中遇到这样的排版验证需求,本质上就是用工程化的手段让普通人也能发现一些翻译排版的问题,因此,实际上,就算你正则表达式非常的烂,甚至一点也不会,你也能弄出一个可以使用的工具来解放生产力。

首先通过交互设计手段来降低我们实现的成本:

  1. 我们没有必要一次性所有的规则一次性匹配,我可以让用户选择具体哪条规则,到时候一个一个规则匹配就好了,用户完全不care的;
  2. 没有必要匹配所有的排版规则,比方说最后单词英文后面是全角标点,整句英文还使用半角标点,有些难度,也有些蛋疼,我们大不了忽略。因为本来就是辅助工具,没必要面面俱到。

然后,判断什么类型的字符,可以不用走高大上、学习成本较高的正则表达式,可以试试基于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

例如,我点击第一个检查按钮,成功高亮的不合要求的排版内容:

uEZVfm3.png!web

就一个循环外加一大堆if语句,一丁点正则表达式都没实现,就实现了看上去很难的翻译排版校验工具,而且多半比正则实现更稳健。

页面源码可以直接在这个项目的docs目录中找到: https://github.com/zhangxinxu/quiz

五、升职加薪与技术强弱没有直接关系

接下来要引出本次直播答疑最有价值的一个议题,是有关职业发展的,那就是升职加薪与技术强弱没有直接关系。

很多人都有这样一个错误的认识,因为自己的技术越强,薪资就越高,职位就越高,实际上不是这样子的,并没有直接的关系。职位的高低是与你对团队,对公司产生的价值相呼应的。作为一个技术人员,就算你的技术能力并不是非常的强,也能产生非常高的价值,关键在于认知与意识。

举个例子,某公司某团队打算加入掘金的翻译计划,来提高团队的影响力。

其中有个很重要的环节,那就是校验,而校验这种工作往往都是团队的负责人来做这个事情,负责最后的把关,免得出现一些意外的风险。这就问题来了,通常团队的负责人都是很忙的,要靠肉眼去识别那些翻译中出现的小错误,那是非常费心费力费神费时的事情,久而久之,体验会变得非常糟糕。

这个的团队里面有两个前端,一个技术非常扎实,正则玩得666,但总是沉浸在自己的技术世界里,专注于手头上的事情,以自己代码质量世界第一为自豪。另外一个技术一般般,正则玩得233,但是,其敏锐发现翻译排版校验走人工是非常低效的一件事情,于是当机立断决定做了一个工具,可以帮助大家快速的发现一些排版上的问题,解放生产力。虽然技术一般般,但他活用自己已经掌握的一些知识,通过良好的交互设计降低实现成本,用“傻白甜”的方式把这个东西给做出来了,别人一用,嘿,还行。

很显然,这件事情上,那个技术一般般的人创造的价值更大,而且大的非常明显。一个人技术再强,那解放只是你一个人的生产力,团队还有其他好几十号人并没有任何提升;但是如果你做出一个可以让大家都能提高生产力的工具,就算你技术一般般,但是你对这个团队产生的价值是非常深远的。翻译这种事情,全国有那么多人参加,如果你把这个工具开源出去,对团队带来的影响力要远比翻译一两个文章更高。

对比下:技术强的人自己生产力很高,然后没有然后;技术一般般的人让团队其他人生产力提高,同时通过开源工具给团队带来了影响力。如果你是领导,如果你是boss,你会提拔哪一个人?显然,只要领导不是智障,都会升职加薪是后面那个技术一般的人!

很多技术人员一直没有意识到这个问题,经常会抱怨,那个人技术那么烂,为什么这次升职晋升的是他?拜托,升职晋升是看贡献,不是看你一个人的技术水平,这个和搞科研是不一样的,企业是商业机构。

所以,大家一定要扭转意识,敏锐捕捉可以产生巨大价值的场景,不要只盯着自己的一亩三分地。工作中所有同事遇到的不爽、不悦,所有那些重复人力的场合,都是一次很好的提高你绩效的机会,就算你技术一般般,也能产生非常大的价值;如果你本身技术就很强,那更要抓住这样的机会,否则机会留给了别人,最后怎么被踩下去都不知道,那更惨!

六、关于本次直播

本次直播有录播,因为加班错过的小伙伴可以去围观,地址是: https://www.bilibili.com/video/av41104858/

MJNNR3M.png!web

欢迎提出各种意见。

关于群小测

每周三下班后会在微信粉丝群公布一道小测题,每周六上午10:00-11:00会以 直播形式 对大家的解答进行答疑。

目前一群已满,二群还有坑我,想入的可以加我微信好友 zhangxinxu-job,我拉你们进去,备注“入群”,然后附上你们的姓名,方便我备注。

好,本次答疑文字版就到这里。

我要看刀剑去了。

zYFzMra.png!web

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。

本文地址: https://www.zhangxinxu.com/wordpress/?p=8402

(本篇完)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK