愚蠢的地球人


正则表达式入门笔记

一、元字符

元字符是构造正则表达式的一种基本元素。
我们先来记几个常用的元字符:
元字符
说明
.
匹配除换行符以外的任意字符
\w
匹配字母或数字或下划线或汉字
\s
匹配任意的空白符
\d
匹配数字
\b
匹配单词的开始或结束
^
匹配字符串的开始
$
匹配字符串的结束
 
下面,我们开始利用这些元字符来写一些简单的正则表达式:
 
1.匹配由abc开头的字符串:
\babc或者^abc
2.匹配8位数字的QQ号码:
^\d\d\d\d\d\d\d\d$
3.匹配1开头11位数字的手机号码:
^1\d\d\d\d\d\d\d\d\d\d$
 

二、反义

前面说到元字符的都是要匹配什么什么,当然如果你想反着来,不想匹配某些字符,正则也提供了一些常用的反义元字符:
元字符
解释
\W
匹配任意不是字母,数字,下划线,汉字的字符
\S
匹配任意不是空白符的字符
\D
匹配任意非数字的字符
\B
匹配不是单词开头或结束的位置
[^x]
匹配除了x以外的任意字符
[^aeiou]
匹配除了aeiou这几个字母以外的任意字符
 

三、重复限定符(花括号)

有了元字符就可以写不少的正则表达式了,但现在你能写的正则表达式只是一堆乱七八糟而且重复的元字符。正则没提供办法处理这些重复的元字符吗?答案是有的!为了处理这些重复问题,正则表达式中一些重复限定符,把重复部分用合适的限定符替代,下面我们来看一些限定符:
语法
说明
*
重复零次或更多次
+
重复一次或更多次
?
重复零次或一次
{n}
重复n次
{n,}
重复n次或更多次
{n,m}
重复n到m次
 
有了这些限定符之后,我们就可以对之前的正则表达式进行改造了,比如:
 
1.匹配8位数字的QQ号码:
^\d{8}$
2.匹配1开头11位数字的手机号码:
^1\d{10}$
3.匹配银行卡号是14~18位的数字:
^\d{14,18}$
4.匹配以a开头的,0个或多个b结尾的字符串
^ab*$
 

四、分组(圆括号)

从上面的例4中看到,*限定符是作用在与他左边最近的一个字符,那么问题来了,如果我想要ab同时被*限定那怎么办呢?正则表达式中用小括号()来做分组,也就是括号中的内容作为一个整体。因此当我们要匹配多个ab时,我们可以这样,比如匹配字符串中包含0到多个ab开头:
^(ab)*
 
捕获组可以通过从左到右计算其开括号来编号。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。例如,在表达式(A)(B(D)) 中,存在四组,(A)(B(D)), (A), (B(D)), (D),对于分组而言,整个表达式永远算作第0组。
比如对于IP地址的匹配,简单的可以写为如下形式:
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
 
但仔细观察,我们可以发现一定的规律,可以把.\d{1,3}看成一个整体,也就是把他们看成一组,再把这个组重复3次即可。表达式如下:
\d{1,3}(\.\d{1,3}){3}
 
另外,可以使用 Back 引用 是说在后面的表达式中我们可以使用组的编号来引用前面的表达式所捕获到的文本序列。
 
就拿匹配<title>xxx</title>标签来说,简单的正则可以这样写:
<title>.*</title>
 
可以看出,上边表达式中有两个title,完全一样,其实可以通过分组简写。表达式如下:
<(title)>.*</\1>
 

五、转义(反斜杠)

我们看到正则表达式用小括号来做分组,那么问题来了:如果要匹配的字符串中本身就包含小括号,那是不是冲突?应该怎么办?针对这种情况,正则提供了转义的方式,也就是要把这些元字符、限定符或者关键字转义成普通的字符,做法很简答,就是在要转义的字符前面加个斜杠,也就是\即可。比如要匹配以(ab)开头:
^(\(ab\))*
 

六、 条件或(竖线)

回到我们刚才的手机号匹配,我们都知道:国内号码都来自三大网,它们都有属于自己的号段,比如联通有130/131/132/155/156/185/186/145/176等号段,假如让我们匹配一个联通的号码,那按照我们目前所学到的正则,应该无从下手的,因为这里包含了一些并列的条件,也就是“或”,那么在正则中是如何表示“或”的呢?正则用符号 | 来表示或,也叫做分支条件,当满足正则里的分支条件的任何一种条件时,都会当成是匹配成功。那么我们就可以用或条件来处理这个问题
^(130|131|132|155|156|185|186|145|176)\d{8}$
 

七、区间(方括号)

看到上面的例子,是不是还有一种想要简化的冲动?实际是有的,正则提供一个元字符中括号 [] 来表示区间。
  • 限定0到9 可以写成[0-9]
  • 限定A-Z 写成[A-Z]
  • 限定某些数字 [165]
那上面的正则我们还改成这样:
^((13[0-2])|(15[56])|(18[5-6])|145|176)\d{8}$
 

八、非捕获组

以 (?) 开头的组是非捕获组,它不捕获文本,也不针对组合进行计数。就是说,如果小括号中以?号开头,那么这个分组就不会捕获文本,当然也不会有组的编号,因此也不存在后向引用。捕获组捕获的内容是被存储在内存中,可供以后使用,比如反向引用就是引用的内存中存储的捕获组中捕获的内容。而非捕获组则不会捕获文本,也不会将它匹配到的内容单独分组来放到内存中。所以,使用非捕获组较使用捕获组更节省内存。比如:(?:a|A)123(?:b)可以匹配 a123b 或者 A123b
语法
含义
(exp)
匹配 exp,并捕获文本到自动命名的组里
(?<name>exp)
匹配 exp,并捕获文本到名称为 name 的组里,也可以写成 (?'name'exp)
(?:exp)
匹配 exp,不捕获匹配的文本,也不给此分组分配组号
(?=exp)
匹配 exp 前面的位置
(?<=exp)
匹配 exp 后面的位置
(?!exp)
匹配后面跟的不是 exp 的位置
(?<!exp)
匹配前面不是 exp 的位置
(?#comment)
对正则表达式的处理没有任何影响,只是用于提供注释让人阅读
 

九、零宽断言

零宽就是没有宽度,只匹配位置,不匹配内容,就是类似于^、$、\b这种元字符。断言就是说这个位置需要满足一定的条件,用来声明一个应该为真的事实,正则表达式中只有当断言为真时才会继续进行匹配。零宽断言总共有四种形式。前两种是正向零宽断言,后两种是负向零宽断言。
  • (?=exp)叫零宽度正预测先行断言,它断言此位置的后面能匹配表达式exp。比如[a-z]*(?=ing)匹配以ing结尾的单词的前面部分(除了ing以外的部分),查找I love cooking and singing时会匹配出中的cook与sing。先行断言的执行步骤应该是从要匹配字符的最右端找到第一个“ing”,再匹配前面的表达式,如无法匹配则查找第二个“ing”。
  • (?<=exp)叫零宽度正回顾后发断言,它断言此位置的前面能匹配表达式exp。比如(?<=abc).*匹配以abc开头的字符串的后面部分,可以匹配abcdefgabc中的defgabc而不是abcdefg。通过比较很容易看出后发断言和先行断言正好相反:它先从要匹配的字符串的最左端开始查找断言表达式,之后再匹配后面的字符串,如果无法匹配则继续查找第二个断言表达式。
负向零宽断言的两种形式(把 = 换成 !):
  • (?!exp)叫零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp。比如\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词,查找“abc123, ade123”这个字符串,可以匹配出ade123。
  • (?<!exp)叫零宽度负回顾后发断言,断言此位置的前面不能匹配表达式exp。比如(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。还有一个复杂的例子:(?<=<(\w+)>).*(? =</\1>),用于匹配不包含属性的简单HTML标记内的内容。比如可以从 <div>test</div> 中提取出“test”。
举个栗子,正则表达式 (?<!4)56(?=9),匹配后面的文本56前面不能是4,后面必须是9组成。因此,可以匹配 5569 ,与4569不匹配
 

十、贪婪和非贪婪

1.贪婪
在正则中,贪婪就是尽可能多的要。当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符,这匹配方式叫做贪婪匹配。特性:一次性读入整个字符串进行匹配,每当不匹配就舍弃最右边一个字符,继续匹配,依次匹配和舍弃(这种匹配-舍弃的方式也叫做回溯),直到匹配成功或者把整个字符串舍弃完为止,因此它是一种最大化的数据返回,能多不会少。前面我们讲过重复限定符,其实这些限定符就是贪婪量词,比如表达式:
\d{3,6}
用来匹配3到6位数字,在这种情况下,它是一种贪婪模式的匹配,也就是假如字符串里有6个个数字可以匹配,那它就是全部匹配到。
文本:61762828 176 2991 44 871
贪婪模式:\d{3,6}
匹配结果1:617628
匹配结果2:176
匹配结果3:2991
匹配结果4:871
本来字符串中的“61762828”这一段,其实只需要出现3个(617)就已经匹配成功了的,但是他并不满足,而是匹配到了最大能匹配的字符,也就是6个。如果多个贪婪量词凑在一起,如果字符串能满足他们各自最大程度的匹配时,就互不干扰,但如果不能满足时,会根据深度优先原则,也就是从左到右的每一个贪婪量词,优先最大数量的满足,剩余再分配下一个量词匹配。
文本:61762828 176 2991 87321
贪婪模式:(\d{1,2})(\d{3,4})
匹配结果1:617628
匹配结果2:2991
匹配结果3:87321
"617628" 是前面的\d{1,2}匹配出了61,后面的\d{3,4}匹配出了7628
"2991" 是前面的\d{1,2}匹配出了2 ,后面的\d{3,4}匹配出了991
"87321"是前面的\d{1,2}匹配出了87,后面的\d{3,4}匹配出了321
 
2. 非贪婪
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能少的字符,这匹配方式叫做非贪婪匹配。特性:从左到右,从字符串的最左边开始匹配,每次试图不读入字符匹配,匹配成功,则完成匹配,否则读入一个字符再匹配,依此循环(读入字符、匹配)直到匹配成功或者把字符串的字符匹配完为止。
非贪婪量词是在贪婪量词后面加个“?”
代码
说明
*?
重复任意次,但尽可能少重复
+?
重复1次或更多次,但尽可能少重复
??
重复0次或1次,但尽可能少重复
{n,m}?
重复n到m次,但尽可能少重复
{n,}?
重复n次以上,但尽可能少重复
文本:61762828 176 2991 87321
贪婪模式:(\d{1,2}?)(\d{3,4})
匹配结果1:61762
匹配结果2:2991
匹配结果3:87321
"61762" 是左边的(\d{1,2}?)匹配出6,右边的(\d{3,4})匹配出1762
"2991" 是左边的(\d{1,2}?)匹配出2,右边的(\d{3,4})匹配出991
"87321" 是左边的(\d{1,2}?)匹配出8,右边的(\d{3,4})匹配出7321

威联通(QNAP)NAS配置优化笔记

一、硬盘单独休眠
1.查看:

mdadm -D /dev/md9
mdadm -D /dev/md13
hdparm -C /dev/sdc
hdparm -C /dev/sda


2.建立脚本文件disconnect_internal_raid.sh:

#!/bin/sh
echo "Disconnecting md9"
mdadm /dev/md9 --fail /dev/sdc1
mdadm /dev/md9 --fail /dev/sda1
echo "Disconnecting md13"
mdadm /dev/md13 --fail /dev/sdc4
mdadm /dev/md13 --fail /dev/sda4


3.建立脚本文件rebuild_internal_raid.sh:

More...


删除Mac OS文件系统的附加属性

有时候在Mac系统下读写NTFS分区时,会发现一些文件不能打开。提示错误为:
    项目“XXX”已被OS X使用,不能打开。
出现这种情况往往是因为文件被添加了附加属性。

ls -al 命令可以看到:
    -rwxr-xr-x@
文件的读写权限中被加上了一个@符号,这就是 Mac OS X 文件系统的附加属性(extended attributes)。

查看详细的附加属性内容:
    xattr -l filename

彻底删除附加属性的办法:
    xattr -c filename
去除当前文件夹中所有 txt 的附加属性。再次 ls -al 可以发现没有了@符号。

某些博客和贴吧推荐的:
    xattr -d com.apple.FinderInfo XXX.txt
或者其他带有com.apple.****的都可能删除不彻底。只有用-c 参数才能彻底删除。

清除目录下所有文件的属性
    find . -name "*.*" -exec xattr -c {} \;
或者:
    find . -type f -print0 | xargs -0 xattr -c

还有更简单的指令:
    xattr -c -r path
或者
    xattr -rc path

如果路径中有空格或特殊字符的长路径:
打开Terminal.app并开始输入xattr -rc,包含尾随空格,然后将文件或文件夹拖到Terminal.app窗口,它将自动添加正确转义的完整路径。


Mac和Windows双系统共用蓝牙设备无需重新配对

转自https://github.com/digitalbirdo/BT-LinkkeySync/issues/12

一、生成Mac系统下的蓝牙配置文件

首先在Mac系统下配对蓝牙鼠标,配对之前可以先删除系统的蓝牙配对文件:

sudo rm  /private/var/root/Library/Preferences/com.apple.bluetoothd.plist
sudo rm /Library/Preferences/com.apple.Bluetooth.plist

配对鼠标,然后导出配置文件供以后修改:

More...


光猫绑定VLAN解决网络和IPTV共用一根网线的问题

装修时弱电箱到客厅只预埋了一根网线,但这时要同时连路由器上网和观看IPTV怎么办?
通常的做法是单网线8芯分双线4芯解决方案(某宝有成品网线一分二)。原理是使用百兆网络时,网线只用1、2、3、6,其余是闲置的,一般网线都是8芯,所以解决方案就是用4芯来接一个水晶头,这样就可以把一根网线变两根。
但是现在家用宽带的带宽基本都超过100兆了,如果用这种办法就会浪费上网的带宽,有没有更好的解决方案呢?
我曾经试过电力猫,但是非常不稳定,很多号称百兆的电力猫,在实际的电力使用环境下,连10兆的稳定连接都不能保证,后来我花高价换了一对号称千兆的电力猫,刚换上的时候非常稳,看高清节目都很流畅。结果半年不到,就莫名其妙的发卡了,现在都基本没法正常观看节目了。
最完美的解决方案是利用VLAN,将Internet和IPTV绑定到光猫的同一个LAN口,然后再用一台VLAN交换机将Internet和IPTV数据分到两个接口上。
首先,登录光猫的管理后台,各地不同运营商不同的光猫登录地址账号密码都不一样,请自行百度。

More...


OpenWrt路由器下面设备直接访问光猫

目前大部分的家庭宽带都是路由器的WAN口直接连接光猫的LAN口,光猫设置为桥接模式,路由器进行PPPOE拨号上网。假如光猫的LAN口地址为192.168.0.1,路由器的LAN口IP地址为192.168.1.1,电脑通过DHCP获取到的IP地址为192.168.1.100。如果想访问路由器的管理页面,很简单,直接通过浏览器访问http://192.168.1.1就可以。但是由于电脑跟光猫不在同一个局域网,所以电脑上无法直接通过192.168.0.1这个地址来访问光猫。如果想要访问光猫的管理页面就只能重新找根网线直接将电脑跟光猫的LAN口连接,然后手动设置电脑的IP地址为192.168.0.x,这样才能访问,比较麻烦。有没有什么办法能直接从192.168.1.100访问192.168.0.1呢?如果你使用的的是OpenWrt的路由器,这里介绍两种办法。

More...


威联通Container Station安装Gateone踩坑笔记

通常情况下,在Windows系统下通过SSH登录家里的NAS系统或者是登录Openwrt路由器,我一般使用Putty。家里内网中NAS主机或者Openwrt路由器想要从外网SSH登录的话需要在路由器上做端口映射,但是把NAS跟路由器的的SSH端口暴露在公网上可能会有一些安全性的问题。后来我发现了一个叫Gateone的神器,这是一个能在浏览器上运行的SSH客户端。只要有一个支持HTML5的现代浏览器你就能SSH登录到linux服务器。而且如果你把Gateone部署在内网中,你就可以在外网的浏览器上先连接到gateone,然后直接输入内网的IP来登录内网中的linux主机。其实说实话,除了装B之外并没有多大的实际意义,想象一下你在高铁上或者咖啡厅里优雅的拿出ipad打开safari然后SSH登录家里NAS的情景。

正文开始
1.添加Docker Hub的镜像服务器。
Gateone的docker镜像文件有好几百MB,国内连接Docker官方服务器比较慢,所以最好是使用国内的镜像服务器。
打开Container Station,在属性的Registry里面添加镜像服务器,我使用的是阿里云的镜像服务。

More...


单网口软路由配合VLAN交换机单线复用原理分析

趁着6.18大促,入手了一台威联通TS-453Bmini。之所以选这款机器主要是看中了它双网口的配置,想利用它来做一个软路由,另外还有HDMI接口,可以用做HTPC。


一开始设计的方案是一个网口做WAN,另一个网口做LAN。但是这个方案有一个致命的缺陷:一旦LAN口用于PC和NAS之间拷贝数据,这个LAN口的千兆带宽会被完全占用,这时候其他设备再通过这个LAN口访问外网的速度肯定会受影响。所以最后我定下来的方案是保留一个网口供NAS专用,另一个网口做一个单网口的软路由。另外,为了维护的方便,我将原来的硬路由保留下来作为备用,平时不通电,当NAS升级或者维护的时候只需要拔下软路由跟交换机之间的网线然后将备用的硬路由插上电源即可。整个网络的拓扑图如下:

More...


用WinSCP以root权限登录群晖DSM6.2.2

使用putty连接DSM,admin账号登录成功后,输入sudo -i

会提示输入密码password,这边还是输入admin的密码。

看到root@……:~#这样的信息就是已经进入到root账号了。

设置root账号密码,输入synouser --setpw root password 这里的password最好和admin密码一样,这样不容易搞错。

输入vi /etc/sudoers,按i键进入编辑模式,找到%administrators ALL=(ALL) ALL改为ALL=NOPASSWD: ALL,修改完之后按ESC输入:wq回车保存退出。

输入vi /etc/ssh/sshd_config 修改ssh配置文件,按i键进入编辑模式,修改#PermitRootLogin prohibit-password 为 PermitRootLogin yes,然后按ESC键输入:wq回车保存退出。

编辑文件时如果提示没有权限,可以先执行chmod -R 755 /etc/sudoers

输入reboot重启DSM

然后打开winscp高级站点设置 -> 环境 -> SCP/Shell,把Shell的默认改成sudo su - 然后直接登录就是root了