常用正则表达式最强整理(速查手册)

  1. 数字:^[0-9]*$
  2. n位的数字:^\\d{n}$
  3. 至少n位的数字:^\\d{n,}$
  4. m-n位的数字:^\\d{m,n}$
  5. 零和非零开头的数字:^(0|[1-9][0-9]*)$
  6. 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
  7. 带1-2位小数的正数或负数:^(\\-)?\\d+(\\.\\d{1,2})?$
  8. 正数、负数、和小数:^(\\-|\\+)?\\d+(\\.\\d+)?$
  9. 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
  10. 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
  11. 非零的正整数:^[1-9]\\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\\+?[1-9][0-9]*$
  12. 非零的负整数:^\\-[1-9][]0-9\”*$ 或 ^-[1-9]\\d*$
  13. 非负整数:^\\d+$ 或 ^[1-9]\\d*|0$
  14. 非正整数:^-[1-9]\\d*|0$ 或 ^((-\\d+)|(0+))$
  15. 非负浮点数:^\\d+(\\.\\d+)?$ 或 ^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*|0?\\.0+|0$
  16. 非正浮点数:^((-\\d+(\\.\\d+)?)|(0+(\\.0+)?))$ 或 ^(-([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*))|0?\\.0+|0$
  17. 正浮点数:^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$ 或 ^(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*))$
  18. 负浮点数:^-([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*)$ 或 ^(-(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
  19. 浮点数:^(-?\\d+)(\\.\\d+)?$ 或 ^-?([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*|0?\\.0+|0)$
  1. 汉字:^[\\u4e00-\\u9fa5]{0,}$
  2. 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
  3. 长度为3-20的所有字符:^.{3,20}$
  4. 由26个英文字母组成的字符串:^[A-Za-z]+$
  5. 由26个大写英文字母组成的字符串:^[A-Z]+$
  6. 由26个小写英文字母组成的字符串:^[a-z]+$
  7. 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
  8. 由数字、26个英文字母或者下划线组成的字符串:^\\w+$ 或 ^\\w{3,20}
  9. 中文、英文、数字包括下划线:^[\\u4E00-\\u9FA5A-Za-z0-9_]+$
  10. 中文、英文、数字但不包括下划线等符号:^[\\u4E00-\\u9FA5A-Za-z0-9]+$ 或 ^[\\u4E00-\\u9FA5A-Za-z0-9]{2,20}$
  11. 可以输入含有^%&\’,;=?$\\\”等字符:[^%&\’,;=?$\\x22]+
  12. 禁止输入含有~的字符[^~\\x22]+

.*匹配除 \\n 以外的任何字符。

/[\\u4E00-\\u9FA5]/ 汉字

/[\\uFF00-\\uFFFF]/ 全角符号

/[\\u0000-\\u00FF]/ 半角符号

  1. Email地址:^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$
  2. 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
  3. InternetURL:[a-zA-z]+://[^\\s]* 或 ^http://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?$
  4. 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$
  5. 电话号码(\”XXX-XXXXXXX\”、\”XXXX-XXXXXXXX\”、\”XXX-XXXXXXX\”、\”XXX-XXXXXXXX\”、\”XXXXXXX\”和\”XXXXXXXX):^(\\(\\d{3,4}-)|\\d{3.4}-)?\\d{7,8}$
  6. 国内电话号码(0511-4405222、021-87888822):\\d{3}-\\d{8}|\\d{4}-\\d{7}
  7. 身份证号(15位、18位数字):^\\d{15}|\\d{18}$
  8. 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
  9. 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
  10. 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\\w{5,17}$
  11. 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
  12. 日期格式:^\\d{4}-\\d{1,2}-\\d{1,2}
  13. 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
  14. 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$

1.有四种钱的表示形式我们可以接受:\”10000.00\” 和 \”10,000.00\”, 和没有 \”分\” 的 \”10000\” 和 \”10,000\”:^[1-9][0-9]*$

2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符\”0\”不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$

3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$

4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$

5.必须说明的是,小数点后面至少应该有1位数,所以\”10.\”是不通过的,但是 \”10\” 和 \”10.2\” 是通过的:^[0-9]+(.[0-9]{2})?$

6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$

7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$

8.1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$

备注:这就是最终结果了,别忘了+可以用*替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里

  1. xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\\\.[x|X][m|M][l|L]$
  2. 中文字符的正则表达式:[\\u4e00-\\u9fa5]
  3. 双字节字符:[^\\x00-\\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
  4. 空白行的正则表达式:\\n\\s*\\r (可以用来删除空白行)
  5. HTML标记的正则表达式:<(\\S*?)[^>]*>.*?</\\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
  6. 首尾空白字符的正则表达式:^\\s*|\\s*$或(^\\s*)|(\\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
  7. 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
  8. 中国邮政编码:[1-9]\\d{5}(?!\\d) (中国邮政编码为6位数字)
  9. IP地址:\\d+\\.\\d+\\.\\d+\\.\\d+ (提取IP地址时有用)
  10. IP地址:((?:(?:25[0-5]|2[0-4]\\\\d|[01]?\\\\d?\\\\d)\\\\.){3}(?:25[0-5]|2[0-4]\\\\d|[01]?\\\\d?\\\\d))
  11. IP-v4地址:\\\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b (提取IP地址时有用)
  12. 校验IP-v6地址:(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))
  13. 子网掩码:((?:(?:25[0-5]|2[0-4]\\\\d|[01]?\\\\d?\\\\d)\\\\.){3}(?:25[0-5]|2[0-4]\\\\d|[01]?\\\\d?\\\\d))
  14. 校验日期:^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$(“yyyy-mm-dd“ 格式的日期校验,已考虑平闰年。)
  15. 抽取注释:<!–(.*?)–>
  16. 查找CSS属性:^\\\\s*[a-zA-Z\\\\-]+\\\\s*[:]{1}\\\\s[a-zA-Z0-9\\\\s.#]+[;]{1}
  17. 提取页面超链接:(<a\\\\s*(?!.*\\\\brel=)[^>]*)(href=\”https?:\\\\/\\\\/)((?!(?:(?:www\\\\.)?\’.implode(\’|(?:www\\\\.)?\’, $follow_list).\’))[^\” rel=\”external nofollow\” ]+)\”((?!.*\\\\brel=)[^>]*)(?:[^>]*)>
  18. 提取网页图片:\\\\< *[img][^\\\\\\\\>]*[src] *= *[\\\\\”\\\\\’]{0,1}([^\\\\\”\\\\\’\\\\ >]*)
  19. 提取网页颜色代码:^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$
  20. 文件扩展名效验:^([a-zA-Z]\\\\:|\\\\\\\\)\\\\\\\\([^\\\\\\\\]+\\\\\\\\)*[^\\\\/:*?\”<>|]+\\\\.txt(l)?$
  21. 判断IE版本:^.*MSIE [5-8](?:\\\\.[0-9]+)?(?!.*Trident\\\\/[5-9]\\\\.0).*$

不说概念了!直接告诉你这些常用正则表达式是怎么写出来的

作为一名程序员,不会写正则表达式总感觉少了点什么,不要求你能把正则玩出花来,但最起码要对常用的正则表达式手到擒来,刚毕业的我对于正则也是一头雾水,不过学会它也就一篇教程的事情[1]

本文我不会再浪费带宽把正则的规则再次重复一遍,而是从实际入手,直接告诉你为什么这么写

16进制颜色

按照规则来

  1. # 开头
  2. 后面紧跟着6个字符或者3个字符作为结尾,这些字符可以是 a-f 的小写字母、A-F的大写字母、数字

第一句,可以写成 /^#/;第二句,[a-fA-F0-9] 表示任意的 a-f、A-F、0-9,6或 3的个数可以用 {6}、{3}进行表示,那么3个字符就是 [a-fA-F0-9]{3},6个字符就是 [a-fA-F0-9]{6},这两个都有可能,用一个或(|)符号来连接:([a-fA-F0-9]{6}|[a-fA-F0-9]{3}),最后结尾可以用个 $

所有合到一起就是 /^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/

链接

目标是匹配出协议、域名、端口号port、path、search

  1. 协议

合法的协议有 http、https,还有一个是自适应协议,即不明确加协议,跟当前页面的协议保持一致,所以以下都是合法的:http://toutiao.com、https://toutiao.com、//toutiao.com。这三个协议组成的链接共同点是肯定有 // 字符串,在 //的前面可能是 https: 也可能是 http: 也可以没有任何字符串 先按照 https:// 这种写规则:^https:\\/\\/,其中的 s 字符可能有也可能没有,所以使用 ? 修饰:^https?:\\/\\/,又因为 https?:可能没有,所以这个字符串也用 ?修饰:^(https?:)?\\/\\/

  1. 域名

域名的前面可能是 //,从 //往后面匹配,只要没有代表 :的 port、代表 search 的 ?、代表 path的 /,那么就都属于域名:[^?:/]+

  1. 端口号 port

端口号肯定以 : 开头,后面跟着的只要是数字就都属于 port::\\d+,由于不一定有端口号,所以用 ? 修饰:(:\\d+)?

  1. path

肯定以 / 开头,只要不遇到代表 search 的 ?,那么就都属于 path:\\/[^?]*,由于可能没有 path,所以用 ? 修饰:(\\/[^?]*)? 5. search 肯定以 ? 开头,后面所有的字符都属于 search(不考虑 hash 路由):\\?(.*),由于可能没有 search,所以用 ? 修饰:(\\?.*)?

最后把上面所有规则合起来就是提取链接的完整正则了,考虑到需要精确提取所需要的部分,所以会对所需要提取的部分加上小括号,结果为:/^((https?):)?\\/\\/([^?:/]+)(:(\\d+))?(\\/[^?]*)?(\\?(.*))?/

邮箱

以前在知乎上看到过一段邮箱正则,号称是最符合标准的正则表达式,那条正则的体积好像有几十KB吧,总之很长,现在找不到了,这里只关注常用的邮箱格式,规则:名称允许汉字、字母、数字,下划线,中划线,域名可以有数字、字母、下划线、中划线组成

汉字的范围是 [\\u4e00-\\u9fa5],字母的范围是 [a-zA-Z],数字的范围是 [0-9],合起来组成邮箱的名称 ^[A-Za-z0-9-_\\u4e00-\\u9fa5]+

域名是 [a-zA-Z0-9_-]+,域名后缀可以是多级域名 (\\.[a-zA-Z0-9_-]+)+

上面组合起来就是 ^[A-Za-z0-9-_\\u4e00-\\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$

手机号

手机号的号段可能是会增加的,所以在实际场景中不建议限制得太死了

本正则按照以下规则编写:

  1. 11位数字,以数字 1 开头,即 ^1
  2. 接下来的数字如果是 3,那么 3后面可以跟一个任意数字,即 3\\d;如果是 4,那么 4后面可以跟一个5-9之间的数字,即 4[5-9];如果是 5,那么 5后面可以跟一个0-35-9之间的数字,即 5[0-35-9];如果是 6,那么 6后面可以跟 2567 其中一个数字,即 6[2567];如果是 7,那么 7后面可以跟一个0-8之间的数字,即 7[0-8];如果是 8,那么 8后面可以跟一个任意数字,即 8\\d;如果是 9,那么 9后面可以跟一个0-35-9之间的数字,即 9[0-35-9]
  3. 最后 8位可以是任意数字

上述三步合起来就是 /^1(3\\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$/

数字/货币金额

  1. 支持负数

负号用 -负号,且必须在第一位,即 ^-,再加个 ? 用于表示这个负号可以有也可以没有,即 ^-? 2. 支持千分位分隔(没有也没关系) 如果有千分位,则千分位的后面必然跟着三位数字(否则这个千分号就不应该加了),千分位前面最少一位、最多三位数字,那么可以写成 \\d{1,3},\\d{3},再精简下,千分位前面的数字其实可以不用限制,因为只要超过三位肯定就有千分位,就会被 \\d{3}捕获,所以 \\d{1,3}换成 \\d+就行了,因为符合千分位的可以有多个也可能没有,所以写成 \\d+(,\\d{3})* 3. 如果有小数,则小数点后最多两位 小数点就是 \\.,后面跟着最多两位数字 \\d{1,2},可能有小数也可能没有,所以整体需要再加个 ? 符号,即 (\\.\\d{1,2})?

最终规则 /^-?\\d+(,\\d{3})*(\\.\\d{1,2})?$/

身份证号

这里只看 2代身份证,18位数字 最后一位是校验位,可能为数字或字符X

  1. 第一位数字在 [1-9] 闭区间内,后面紧跟着5位任意数字,写成 ^[1-9]\\d{5}
  2. 再紧跟着的四位数字代表年份(YYYY),因为目前有身份证的人最早是19世纪最晚21世纪,所以这四个数字中的前两位只看是 181920,即 (18|19|20),后两位则可以是任意数字,即 \\d{2}
  3. 再紧跟着两位数字是月(MM),月份只可能是 [1-12]闭区间,所以可以写成 (01|02|03|04|05|06|07|08|09|10|11|12),前九位的开头都是 0,第二位是 [1-9] 内的数字,所以简化成 (0[1-9]|10|11|12)
  4. 再紧跟着两位数字是日(DD),范围是 [01-31],可以将这31个数字罗列出来,当然也可以精简下,看成是 [00-09][10-29][30-31]的组合,即 (0[1-9]|[1-2]\\d|30|31)
  5. 再紧跟着三位数字是顺序码,即 \\d{3}
  6. 最后一位是校验码,可以是数字也可以是 X,即 [\\dX]

最终规则 /^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|10|11|12)(0[1-9]|[1-2]\\d|30|31)\\d{3}[\\dX]$/

密码校验

最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符

对于 至少1个大写字母 这条规则,这个大写字母的位置是不固定的,只要有就行,如果只有这一条规则的话,正则可以写成 ^\\S*[A-Z]+\\S*$,\\S 匹配任意非空白字符,这个规则即代表大写字母的前面、后面可以跟着任意个(包括0个)非空白字符

但除此之外还需要满足最少1个小写字母,1个数字,1个特殊字符,最少6位,你可以将这几条规则都单独写出正则,然后目标字符串跟这5条正则一一匹配,只要全部能匹配上就是对的,写成 js 代码就是:

如果就想在一条正则里实现这些校验呢,也是可以的,需要借助 零宽度正预测先行断言(?=exp)),代表 匹配exp前面的位置

有了这个东西,就可以把上面5条规则写到一起去了:/^\\S*(?=\\S{6,})(?=\\S*\\d)(?=\\S*[A-Z])(?=\\S*[a-z])(?=\\S*[!@#$%^&*?])\\S*$/

这条正则前面后面的 \\S* 还是之前的意思不变,中间是提取了5条规则的个性部分,然后通过 ?= 放在一起了,把规则里所有的 ?=去掉行不行?不行,因为如果去掉的话,首先就有顺序上的冲突了,例如上面的规则,如果把所有的 ?=去掉,就代表着 数字必须在大写字母前面,大写字母必须在小写字母前面,特殊字母必须在小写字母前面(除此之外整个正则也是有问题的)

你可以认为 ?= 在匹配的时候会忽略掉其他的 ?=,只关心自己的前面能不能匹配成功,有多个 ?=,则这多个 ?= 都是只关心自己,忽略其他,但整条正则最后的结果是所有 ?= 匹配结果的并集,计算逻辑和上面的 js 是差不多的

提取 HTML 标签数据

要提取的标签字符串类似于 <div class=\”header-box\” name=\”header\”>

只是正则话无法完成,需要借助 js

首先,把标签的属性提取出来

这段标签包含标签开始符号、tag、属性字符串、标签结束符号

开始符号是 <,标签名紧跟着开始符号,且只要没遇到空白符就都是标签名,所以连起来就是 <\\w+\\s*

在开始符号+标签名,和 结束符号的中间,都是属性,结束符号是 >,所以只要没遇到结束符号 >,就认为是属性字符串,用到了反向选择 [^>]*\\s*>,合起来就是 /<\\w+\\s*[^>]*\\s*>/,为了能捕获属性字符串,加个小括号,即 /<\\w+\\s*([^>]*)\\s*>/

取到了 class=\”header-box\” name=\”header\” 之后,再对其进行处理,观察规律,每个属性的键值对之间肯定存在空白符,不过却不能通过空白符来直接分割,因为属性值是可以存在空白符的,例如 class=\”a b\”

由于可能是自闭合标签,自闭合标签的最后有没有 / 都是合法的,例如 <hr> 和 hr />都是合法的,所以需要兼容下:/<\\w+\\s*([^>]*)\\s*\\/?>/

但属性名是可以确定的,它可能是 = 左边不包括空白符的内容,再次用到反向选择,从左往右匹配,反向选择既不是=也不是不是空白符的内容,即 [^\\s=]+

虽然不确定属性值是否包含空白符,但有个是确定的,即属性值必然被引号包围,所以直接取 = 右侧所有引号的内容即可,=\”.*?\”

不过还有个问题,引号不仅可以是单引号还可以是双引号,即 =\”.*?\” 和 =\’.*?\’ 都行,如果第一个引号是双引号开头那么对应的第二个引号也必然是双引号,反义单引号亦然,这里需要用到捕获的规则了 =([\”\’]).*?\\1,\\1的意思是这块匹配的内容跟第一捕获组一样,第一捕获组也就是 [\”\’],如果第一捕获组匹配的是双引号,那么 \\1 就代表双引号,否则就代表单引号

至此整个正则为 [^\\s=]+=([\”\’]).*?\\1

不过还有个问题,属性是可以没有属性值的,例如 <input type=\”checkbox\” checked />,这里 checked 就是可以不写属性值的,所以再兼容下:/[^\\s=]+(=([\”\’]).*?\\2)?/,又因为希望捕捉属性和属性值,所以给属性和属性值加个小括号:/([^\\s=]+)(=([\”\’])(.*?)\\3)?/

上面的代表就可以继续写了

小结

学会正则的最接途径就是勤加练习,平时遇到可以用正则解决的问题,就尝试着正则解决,或许你一开始写不出来,但可以去网上看看别人是怎么写的,再自己独立写一遍,写得多了自然就会了,没什么诀窍,无非就是对正则规则的熟练掌握罢了

关于本文

https://juejin.cn/post/7073360739410378760

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。