本周一篇指摘 Vue 抄袭 Angular 的文章一石激起千层浪。为此,笔者作为中立吃瓜的 React 用户,分析了 13 个主流前端框架版本上万个变量的命名风格,应用自然语言处理中的文本相似度算法进行了分析,以对这一论点的有效性做出客观的评价。

思路

在分析书籍抄袭、论文查重等场景下,使用算法比较文本相似度的方法是一种有效的技术手段。那么,我们如何通过这一手段,来分析源码层面的抄袭呢?

在对比形如 我喜欢写代码,不喜欢撕逼我不喜欢撕逼,喜欢写代码 的两个句子相似度时,大致的思路是首先分词,而后计算出词频,再将词频向量化,最后比较两个高维向量的夹角,夹角越小则越相似。

在【Vue 是否抄袭了 Angular】这一场景下,我们分析的对象从句子变成了代码。这时主要的区别是这两点:

  1. 代码是高度结构化的文本,分词已经通过词法分析器完成了。
  2. 某种编程语言的代码中,充斥着大量该语言的关键字。如 varfunction 的关键字,这些关键字的重复与相似度无关。

而对于是否抄袭与相似度的关系,我们给出这几个假设:

  1. 解决同样的开放性问题时,独立编写、不存在抄袭的代码,以变量名为代表的编码风格通常有巨大的差别,此时相似度是低的
  2. 存在较大规模抄袭的代码,类似于同一个框架,未经大规模重构的不同版本代码。此时编码风格是类似的,此时相似度是高的
  3. 前后调换模块声明顺序,不影响相似度

给定这几个前提后,我们可以确定出这样的分析策略:

  1. 输入各大框架未经压缩的源码,解析出其语法树。
  2. 舍弃语法树中无关部分,提取出其变量声明以代表其编码风格。
  3. 使用文本相似度算法计算变量名间的相似度,分析结论。

变量名提取

在通过 Webpack 引用框架依赖时,通常导入的都是打包成单一文件且未经混淆的框架源码。这是一个非常好的特性。笔者编写了一个简单的 Webpack Loader 以在这个过程中实现变量名的提取:

// loader/index.js
// 为 loader 传入的 content 即为 JS 源码
module.exports = function (content) {return demo(content)
}复制代码

demo 函数中获得框架源码后,解析语法树也不是一个困难的问题了。通过 acorn 这一 Parser 我们就能做到:

function demo (content) {const ast = acorn.parse(content, { sourceType: 'module' })walk.simple(ast, {// 在 walk 遍历时,抽取全部变量声明语句中的变量名VariableDeclaration (node) {const name = node.declarations[0].id.name + '\n'fs.appendFileSync(resolve('./result.txt'), name)}})return content
}复制代码

这时候我们就能在 result.txt 内获得一个前端框架中的全部变量名了,形如:

p
i
resolved
c
segs
i
...复制代码

这都是什么乱七八糟的…这时候我们获得的文本并没有经过初步的处理,我们真正感兴趣的是各个框架变量名的词频。词频的计算是一道不错的面试题,不过在这里我们直接通过 Wordclouds 的服务来实现这一步。这一步中还包括基本的清洗,以去除 i / a / b 这些无意义的变量名。我们的结果是形如这样的格式:

29    value
19    arg
18    result
16    key
14    index
...复制代码

以上就是 React / Vue / Angular 三大框架中某一个的 Top 5 变量名,猜猜是哪一个?好吧这几个变量名都十分烂大街…暂时看不出什么端倪。让我们继续做相似度比较吧,答案在后面揭晓。

相似度算法

我们在上文中,实际上已经获得了这样的对象:

const a = {'foo': 5,'bar': 4,'baz': 3
}
const b = {'foo': 4,'bar': 6,'baz': 0
}复制代码

我们可以认为,每个变量名是一个独立的维度,每个框架中存在的所有类型变量名组成一个高维空间的向量。从而,我们的问题就简化为了如何比较 a 与 b 这两个向量的相似程度。在此引用阮一峰老师的介绍:

我们可以把它们想象成空间中的两条线段,都是从原点([0, 0, ...])出发,指向不同的方向。两条线段之间形成一个夹角,如果夹角为0度,意味着方向相同、线段重合;如果夹角为90度,意味着形成直角,方向完全不相似;如果夹角为180度,意味着方向正好相反。因此,我们可以通过夹角的大小,来判断向量的相似程度。夹角越小,就代表越相似。

theta-1

假定 a 向量是 [x1, y1],b向量是 [x2, y2],那么可以将余弦定理改写成下面的形式,计算出的 cosθ 代表相似度:

theta-2

推广到高维向量的一般情形:

theta-3

根据算法编写出简化的示例代码:

function getTheta () {let x = 0Object.keys(dictAll).forEach(key => {if (dictA[key] && dictB[key]) x += dictA[key] * dictB[key]})let yA = getY(dictA)let yB = getY(dictB)const result = x / (yA * yB)console.log(result)
}复制代码

最后运行我们的分析算法处理上一步的变量名即可:

➜ node analyse vue@2.4.1 vue@2.4.2
0.9436438155995188复制代码

实验结果与总结

一系列铺垫以后,终于到了检验真理的时候了。我们首先基于【相似版本相似度高】的假设,验证 Vue 是否符合这一假设:

➜ node analyse vue@2.4.1 vue@2.4.2
0.9436438155995188复制代码

可以看到,目前最新的 vue 2.4.2 与 2.4.1 之间,确实存在着很高的相似度。接下来比较 vue 最新版与 2.0.0 同一个 Major 版本之间的相似度:

➜ node analyse vue@2.0.0 vue@2.4.2
0.8838059164881868复制代码

相似度有所降低,说明最新版比起去年的 V2,已经有了不小的改动了。再来比较 V2 与 V1 系列的相似度:

➜ node analyse vue@2.0.0 vue@1.0.28
0.5883193867742227复制代码

相似度明显降低,显然重构之言非虚。最后比较 Vue 的最新版与第一个版本:

➜ node analyse vue@2.4.2 vue@0.6.0
0.4590386014371645复制代码

这是 Vue 家族中最低的相似度,也达到了 0.45 的水平。接下来是正戏,比较 Vue 和 Angular 的最新版:

➜ node analyse vue@2.4.2 angular@4.3.3
0.19322280449484375复制代码

区区 0.19 的相似度!好吧,Angular 最新版也是重构过的,我们不妨直接比较最早【照着 Angular 抄的】的 Vue 和 Angular 1.x 系列:

➜ node analyse vue@0.6.0 angular@1.2.32
0.294527560626686复制代码

这个相似度也大幅低于 Vue 全系列纵向对比的相似度!为了更有效地对比,我们让隔壁 React 躺个枪(未加版本号代表最新版):

➜ node analyse vue@2.4.2 react
0.27592736925848194复制代码

0.27 与 0.29 的对比,说明即便是最早阶段(与 Angular 相似度最高)的 Vue,相似度也仅仅相当于现在的 Vue 和 React 而已!为了保证公平,我们让 jQuery 也来凑个热闹:

➜ node analyse jquery angular@1.2.32
0.2508302720623658复制代码

这也是不到 0.3 的相似度,据此我们甚至可以得出一个大胆的结论:Vue 和 Angular 的相似度,和 Angular 与 jQuery 之间的相似度接近!没有人会认为 jQuery 与 Angular 之间存在抄袭吧?

当然,Vue 和 Angular 的相似度是客观存在的。我们在前端领域,可以找到另一对这样的例子:jQuery VS Zepto,它们之间的相似度如何呢?

➜ node analyse jquery zepto
0.25994377334635854复制代码

这个相似度和 Angular VS jQuery 几乎相同,这说明即便设计理念相近,具体实现不同的原创框架之间,相似度也是很低的。Vue VS Angular 也完全符合这一结论。

hmmm 目前我们的论据已经比较充分了。最后,我们比较一种情形:设计理念完全不同的原创框架之间,相似度如何?我们拉出 jQuery 和 React:

➜ node analyse jquery react
0.1007248324385447复制代码

全场最低相似度…所以我们可以理解 jQuery 时代的前端转向 React 时有多么不习惯了吧?

到此为止,我们的结论有:

  • Vue 系列迭代间相似度较高。
  • 即便是最早的 Vue,与经典 Angular 的相似度也很低。
  • 最新 Vue 与最新 Angular 之间,相似度更低,说明二者的发展道路早已更加独立。
  • 即便设计理念相近,具体实现不同的原创框架之间,相似度也很低。
  • React 与 jQuery 的相似度特别特别低(离题了)。

据此,笔者有理由认为【Vue 抄袭了 Angular】的论点是站不住脚的。

本文的实验数据托管在 Github 上,欢迎感兴趣的同学验证并改进这些结论。最后,框架毕竟只是工具,相互撕逼并不利于社区的发展。引用我司 Boss 的观点:【一流的人做事,二流的人去评论,三流的人去评论别人的评论】,希望大家能把口水战的时间放在更务实的事情上,推动技术水平、社区氛围和平均工资的上升……

基于文本相似度算法,分析 Vue 是抄出来的框架吗?相关推荐

  1. 详解利用基于gensim的TF-IDF算法实现基于文本相似度的推荐算法

    详解利用基于gensim的TF-IDF算法实现基于文本相似度的推荐算法 TF-IDF的基本原理 算法思想 计算公式 相似度计算原理 微型图书推荐案例 案例背景 开发工具 数据预处理 TF-IDF模型建 ...

  2. python中文相似度_基于TF-IDF、余弦相似度算法实现文本相似度算法的Python应用

    基于TF-IDF算法.余弦相似度算法实现相似文本推荐--文本相似度算法,主要应用于文本聚类.相似文本推荐等场景. 设计说明 使用jieba切词,设置自定义字典 使用TF-IDF算法,找出文章的关键词: ...

  3. java算法余弦定律_自己实现文本相似度算法(余弦定理) - 呼吸的Java - 开源中国社区...

    自己实现文本相似度算法(余弦定理) 52人收藏此文章, 我要收藏 发表于9个月前(2012-03-04 16:59) , 已有5592次阅读 ,共6个评论 最近由于工作项目,需要判断两个txt文本是否 ...

  4. [转]文本相似度算法

    来源:http://www.cnblogs.com/liangxiaxu/archive/2012/05/05/2484972.html 文本相似度算法 1.信息检索中的重要发明TF-IDF 1.1T ...

  5. 文本相似度算法的对比及python实现

    文本相似度算法的对比及python实现 前言 通常我们有这样的需求:对两篇文章或者产品内容进行重复率查询. 为了解决类似的问题,罗列了一些常见的相似度算法,用python代码实现. 五种常见的相似度算 ...

  6. python实现文本相似度算法的对比及

    文本相似度算法的对比及python实现 前言 通常我们有这样的需求:对两篇文章或者产品内容进行重复率查询. 为了解决类似的问题,罗列了一些常见的相似度算法,用python代码实现. 五种常见的相似度算 ...

  7. pbewithmd5anddes算法 对应.net_文本相似度算法之-simhash

    文本相似度算法种类繁多,今天先介绍一种常见的网页去重算法Simhash. 1.什么是simhash simhash是google于2007年发布的一篇论文<Detecting Near-dupl ...

  8. 使用Word2Vec完成基于文本相似度的推荐

    使用 Word2Vec 完成基于文本相似度的推荐 之前的基于文本相似度的推荐使用的是one-hot的词向量,虽然可以使用稀疏向量来存储里面的非0值,但是以这种形式的词向量存在很多问题: 稀疏的向量表达 ...

  9. 【自然语言处理】文本相似度算法:TF-IDF与BM25

    文本相似度算法:TF-IDF与BM25 1.TF-IDF TF(Term Frequency)是指归一化后的词频,IDF(Inverse Document Frequency)是指逆文档频率.给定一个 ...

最新文章

  1. 为什么会出现__pycache__文件夹?
  2. Py:数据挖掘之对微信朋友圈好友的性别、区域、昵称、签名信息进行情感分析
  3. 【python基础】用字典做一个小型的查询数据库
  4. 解决 wget 使用 https 下载报错的问题
  5. QT实现自定义3D材质
  6. 【Linux】一步一步学Linux——ssh-keyscan命令(179)
  7. String数据类型的应用场景
  8. linux db2 cached太大,cache
  9. 中python执行shell_IPython,在探索中学习编程
  10. 买写真送手机系列 小米9王源限量版预售将在这些小米之家开启
  11. C语言在linux终端下实现2048小游戏:第二版
  12. 人生苦短,不光要用 Python,还要在 VSCode 里用 | 原力计划
  13. spark DataSet与DataFrame的区别
  14. MEF: MSDN 杂志上的文章(6) 一个部件可以有多个导出 !!!
  15. 英特尔核显驱动hd630_英特尔发新处理器,换新 Logo,还把 AMD 吊打了一轮
  16. 高通4G智能路由器WiFi模块芯片-QCA9531
  17. Windows系统怎么换硬盘图标
  18. 将m个相同的球全部放到n个相同的盒子里面有几种放法,盒子不能为空
  19. html link canonical
  20. linux查看docker是否启动命令行,如何通过命令行查看docker服务是否已启动

热门文章

  1. Substance Painter PS 贴图整合
  2. 数字ip和ip的转化(自编版)
  3. windows7家庭普通版(win7 home basic)安装SQL server 2005 开发版
  4. 预渲染插件prerender-spa-plugin使用总结
  5. CTFshow SSRF(web351-360)
  6. 追梦App系列博客——第五次例会总结
  7. 有梦的人生才值得过。
  8. styl类型文件css,CSS 格式的语法
  9. 轻应用能否创造社交营销新商业价值
  10. 计算机视觉论文doc,视觉知觉论文计算机视觉论文:计算机视觉与人类视知觉浅析.doc...