2 minute read

regex

regex 即 regular expression, 常用来匹配某种 pattern

正则有一系列规则, 这里只记录一些转义字符的意义

\w means word
\W means the opposite
\a means ABCabc...
\l means abc...
\u means ABC...
\t means tab
\b means word's boundary in vim use \< \>
\s means space
\d means number
+  means 1 or more
.  means 0 or more
?  means 0 or 1
^  means start
$  means end

when use ungreed search use ?
.*?
.??  .? matched 0 or 1 , .?? will match 0 because of ungreed search
.{m,n}  this will only match m times

regex groups

  • 命名捕获组
"(?<group>[A-Z]+)" #perl
"(?P<group>[A-Z]+)"  #python
  • 非捕获组, 匹配但不作为捕获结果
"(?:[A-Z]+)"
%(pattern)
  • 零宽断言, 即 zero-width assertion, 他们不匹配任何字符, 只是作为匹配字符前缀后缀的断言, 要求匹配字符有特定的前缀后缀
# match the "some" part of "prefix-some-suffix"
"(?<=prefix-)some(?=-suffix)"
# don't match "some" part of "prefix-some-suffix"
"(?<!prefix-)some(?!-suffix)"
" 为所有文件添加前缀
" vim的零宽使用 pattern@=, @!, @<=, @<!,
%s/\v(^|\/)@<=[^\/]+$/prefix_\0/g
  • 大小写转换
# force case insensitivity
(?i)ab
# force case sensitivity
(?-i)ab
" force case insensitivity
\c
" force case insensitivity
\C

Python regex

text = '<div><td valign="top">Moo</td></div>'
pattern = r"<[^>]+>"
re.findall(pattern, text)
re.sub(pattern, r'\1', text)

text = """03:04:53 some
03:05:14 - some
"""
re.findall(r'(\d\d):(\d\d):(\d\d)', text.strip())

# regex in pandas
pd.Series.str.findall
pd.Series.str.extractall
pd.Series.str.extract
pd.Series.str.contains

vim 中的 regex

由于正则表达式用到了很多特殊字符, 而在搜索这些特殊字符时:

比如:(“Hello”)

这里的括号必须加上’\’, 为\(\“Hello\”\) 而这样的例子在代码中非常常见,
所以 vim 使用了四种模式, 并通过在匹配字符串之前加上’\‘+模式代号实现

  1. magic (\m)
  2. very magic (\v)
  3. nomagic (\M)
  4. very nomagic (\V)
:g/\v^$/d                  #删除所有空行

ps:通过 set magic 等命令可以修改默认使用哪一种匹配方式, 一般为 magic

magic 其实可以理解为魔法字符, 即正则字符,
默认情况下 magic 使用一些常见字符不需要加’\’, 比如^$.*等
比如匹配任意括号:

/(.*)                      #因为set magic所以\v不需要

而 nomagic 模式下, 使用正则必须在正则字符前加’\’

/\m(\.\*)

在 very magic 下, 即完整的正则语法

/\v\(.*\)                  #此时不加'\', 会导致.*被认为是一个单元,无法匹配括号

在 very no magic 下, 即直接输入你想要的字符即可, 如果要使用正则, 所有正则符号加’\’

下面是一个将路径中的’'换成’\‘的 vim 命令

:%s/\>\\\(\w\)/\\\\\1/g    #magic
:%s/\v>\\(\w)/\\\\\1/g     #very magic

此处%代表全文, s 代表 substitute, 接着是替代字符串

\v 为 very magic, >为单右边界, \\代表’',括号为单元, \w 为单词, 之后为替代字符串,俩个’'和前面括号里的元素, 这里为’\1’ g 为 global

vim 中的非贪婪匹配

前面可以看到, 有些正则规则通过 ? 实现非贪婪匹配,但是在 vim 中并不可以

ps:贪婪匹配为尽可能多匹配, vim 默认为贪婪匹配,比如 “.*“会匹配到”Hel”lo”这一整个字符串

你需要使用{-}来匹配, 比如:

/\m\(L".\{-}"\)             #magic mode
/\v(L".{-})"                #very magic mode

用来匹配 L”Hel”, 而 lo”则不会被匹配

vim 中的 g command

:g/pattern/z#.5          #display 5 lines around pattern
:g/pattern/t$            #paste lines to the end of the file
:g/pattern/m$            #move lines
:g/pattern/y [register]  #move to the register
:g/pattern/s/$/mytxt     #add txt to the end of lines

regex 中的 change case

  • 某些正则支持替换匹配的字符为大写, 小写

  • Vim, Shell (sed)

They supports \l and \u in the replacement part of a substitution command (using :s). \l converts the next character to lowercase, and \u converts the next character to uppercase. Additionally, \L and \U can convert all following characters in the replacement string, until an \E is encountered.

python 分割字符串

  • 可以利用正则找出所有的数字, 使用非数字分割
import re
txt = "abc 12131 asdas cd12c7qwec8asd7b"
# 在abc之前分割, 所以会出现空字符串
re.split(r"[^0-9]+", txt)
# ['', '12131', '12', '7', '8', '7','']