正則表達式***(Regular Experssion)

正則表達式

正則表達式縮寫為regex、regexp、RE等。他是文本處理極為重要的技術,其應用非常廣泛,shell中處理文本的命令、各種高級編程語言都支持正則表達式,用它可以對字符串按照某種規則進行檢索和替換,

分類

  • BRE:基本正則,grep、sed、vi等軟件支持。vim支持擴展正則
  • ERE:擴展正則,egrep(grep -E)、sed -r等。
  • PCRE:幾乎所有高級語言都是PCRE的變種。Python的RE可以認為是PCRE的子集

基本語法

  • 元字符(matchcharacter)
代碼 說明 舉例
. 匹配除換行符外任意一個字符
[abc] 字符集合,只能表示一個字符位置。匹配所包含的任意一個字符 [abc]匹配plain中的’a’
[^abc] 字符集合,只能表示一個字符位置。匹配出去集合內字符的任意一個字符 [^abc]可以匹配plain中p、l、i、n
[a-z] 字符范圍,也是集合,只能表示一個字符位置。匹配集合所包含的任意一個字符
[^a-z] 字符范圍,也是集合,只能表示一個字符位置。匹配除集合內字符的任意一個字符
\b 匹配單詞邊界 \bb在文本中找到單詞中b開頭的b字符
\B 不匹配單詞的邊界 t\b包含t的單詞但是不以t結尾的t字符,例如write;\Bb不以b開頭的含有B的單詞,例如table
\d [0-9]匹配1位數字
\D [^0-9]匹配一位非數字
\s 匹配1位空白字符,包含換行符、制表符、空格
\S 匹配一位非空白字符
\w 匹配[a-zA-Z0-9_],包括中文的字
\W 匹配\w之外的字符
  • 單行模式:
    .可以匹配所有字符,包括換行符
    ^表示整個字符串開頭,$表示整個字符串的結尾
  • 多行模式:
    .可匹配除換行符之外的字符
    ^表示行收,$表示行尾
    ^表示整個字符串的開始,$表示整個字符串的結尾。開始指的是\n后緊接著的下一個字符,結束指的是\n前的字符

注意:字符串中看不見的換行符,windows中的回車換行符\r\n會影響$的測試。

  • 轉義:凡是在正則表達式中有特殊意義的符號,如果想使用它的本意,請使用\轉義。反斜杠自身,需使用\\;\r、\n是轉義后代表回車、換行
  • 重復
符號 說明 舉例
* 表示前面的正則表達式會重復0次或多次 e\w*單詞e后面有0到任意個非空字符
+ 表示前面的正則表達式重復至少一次 e\w+單詞e后至少有一個非空白字符
? 表示前面的正則表達式會重復0或1次 e\w?單詞e后最多有一個非空白字符
{n} 重復固定的n次 e\w{1}單詞e后面只能有一個非空白字符
{n,} 重復至少n次 e\w{1,}等價e\w+;\w{0,}等價e\w*;e\w{0,1}等價e\w?
{n,m} 重復至少n次,最多m次 e\w{1,10}單詞e后面至少1個,最多是個非空白字符
  • 練習
    • 匹配手機號碼:\d{11}
    • 匹配固定電話號碼\d{3-4}-\d{7-8}
  • 分組
代碼 說明
x|y 匹配x或y
(pattern) 使用小括號制定一個子表達式,也叫分組。捕獲后會自動分配組號從1開始,可以改變優先級
\數字 匹配對應分組
(?:pattern) 如果僅僅為了改變優先級,就不需要捕獲分組
(?<name>exp)(?’name’exp) 分組捕獲,但是可以通過name訪問分組
零寬斷言
(?=exp) 零寬度正預測先行斷言:斷言exp一定在匹配的右邊出現,也就是說斷言后面一定跟個exp
(?<=exp) 零寬度正回顧:后發斷言:斷言exp一定出現在匹配的左邊,業績是前面一定有個exp前綴
負向零寬斷言
(?!exp) 零寬度付預測先行斷言:斷言一定不會在右側
(?<!exp) 零寬度負回顧后發斷言:斷言一定不能出現在左側
注釋
(?#comment) 注釋

總結:分組和捕獲是同一個意思;同時在正則中能用簡單表達式就不要用復雜的

貪婪與非貪婪

正則表達殺死默認是貪婪模式,盡量多匹配更長的字符串。非貪婪模式很簡單就是再重復的符號后加一個”?”,匹配最少的字符串。

代碼 說明
*? 匹配人一次,盡量少重復
+? 匹配至少一次,少重復
?? 匹配0或依次,少重復
{n,}? 匹配至少n次,少重復
{n,m}? 匹配n到m次,,少重復
  • 引擎選項
代碼 說明 Python
IgnoreCase 匹配時忽略大小寫 re.I,re.IGNORECASE
Singleline 單行模式:.可以匹配所有字符,包括\n re.S,re.DOTALL
Multiline 多行模式:^行首,$行尾 re.M,re.MULTILINE
IgnorePatternWhitespace 忽略表達式中的空白字符,如果要使用空白字符用轉義,#可以用來做注釋 re.X,re.VERBOSE

練習

  • 匹配0-999之間的數字 #匹配兩位數 [1]?\d #匹配三位數 ^([1-9]\d\d?|\d)(?!\w+) ^([1-9])\d\d?|\d)\r?$
  • 匹配點分四段式IP
    關于IP地址驗證問題:
    - 可以把數據提取出來后交給IP地址解析庫(socket模塊)處理,解析異常就說明IP有問題,如果正常則表示Ip合法
    
    import socket
    nw = socket.inet_aton('1.2.4.8')    # 輸入IP字符串,返回bytes,如果拋出異常則表示IP不合法
    print(nw,socket.inet_ntoa(nw))  # inet_ntoa是反向解析
    
    - 可以使用復雜正則表達式驗證地址正確性
    
    - 前導0是可以的

    (?:(25[0-5]|2[0-4]\d|[01]?\d\d?).){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)

  • 選出有Ftp的連接,且文件類型是gz或者xz的文件名
    ftp://ftp.astron.com/pub/file/file-5.14.tar.gzftp://ftp.gmplib.org/pub/gmp-5.1.2/gmp-5.1.2.tar.xzftp://ftp.vim.org/pub/vim/unix/vim-7.3.tar.bz2http://anduin.linuxfromscratch.org/sources/LFS/lfs-packages/conglomeration//iana-etc/iana-etc-2.30.tar.bz2http://anduin.linuxfromscratch.org/sources/other/udev-lfs-205-1.tar.bz2http://download.savannah.gnu.org/releases/libpipeline/libpipeline-1.2.4.tar.gzhttp://download.savannah.gnu.org/releases/man-db/man-db-2.6.5.tar.xzhttp://download.savannah.gnu.org/releases/sysvinit/sysvinit-2.88dsf.tar.bz2http://ftp.altlinux.org/pub/people/legion/kbd/kbd-1.15.5.tar.gzhttp://mirror.hust.edu.cn/gnu/autoconf/autoconf-2.69.tar.xzhttp://mirror.hust.edu.cn/gnu/automake/automake-1.14.tar.xz

    <?<=.*ftp.*/>[^/]\.(?:gz|xz)

Python的re

Python使用re模塊提供了正則的處理能力

常量

  • re.M = re.MULTILINE -> 多行模式
  • re.S = re.DOTALL -> 單行模式
  • re.I = re.IGNORECASE -> 忽略大小寫
  • re.X = re.VERBOSE -> 忽略表達式中的空白字符

使用‘|’位或運算符開啟多種選項

方法

  • 編譯
    • re.compile(pattern,flags=0)
      1. 設定flags,編譯模式,返回正則表達式對象
      2. pattern是正則表達式字符串,flags是選項。正則表達式需要被編譯,為了提高效率,這些便宜的結果被保存,下次使用就不需要再次編譯。re的其他方法為提高效率都調用了編譯方法。
  • 單次匹配
    1. re.match(pattern,string,flags=0)/regex.match(string[,pos[,endpos]])match匹配從字符串的開頭匹配,regex對象match方法可以設定開始位置和結束位置。返回match對象
    2. re.search(pattern,string,flags=0)/regex.search(string[,pos[,edpos]])從頭搜索知道第一個匹配,regex對象search方法可以設定開始位置和結束位置,返回match對象
    3. re.fullmatch(pattern,string,flags=0)/regex.match(string[,pos[,endpos]])這個字符串和正則表達式匹配,要完全匹配,多了或少了都不行
    4. 以上三種方法返回的都是match對象
  • 全部匹配
    • re.findall(pattern,string,flags=0)等價于regex.findall(string[,pos[,endpos]])對整個字符串從左到右匹配,返回所有匹配項的列表
    • re.finditer(pattern,string,flags=0)等價于regex.finditer(string[,pos[,endpos]])對整個字符串從左向右匹配,返回所有匹配項的迭代器。每次迭代返回的是match對象
  • 匹配替換
    • re.sub(pattern,replacement,string,count=0,flags=0)使用pattern對字符串string進行匹配,對匹配項使用repl替換。repl可以是string、bytes、function
    • subn(pattern,replacement,string,count=0,flags=0)返回一個元組(new_string,number_of__subs_made)
  • 分割字符串
    • 字符串分割函數不能指定多個字符進行分割,不好用。
    • re.split(pattern,string,maxsplit=0,flags=0)maxsplit指最大分割數,默認是全部分割
    import re
    
    s = '''01 bottle
    02 bag
    03      big1
    100       able'''
    
    print(s.split())    #做不到
    ret = re.split('[\s\d]+',s)
    print(1,ret)
    regex = re.compile('^[\s\d]+')
    ret = regex.split(s)
    print(2,ret)
    regex = re.compile('^[\s\d]+',re.M)
    ret = regex.split(s)
    print(3,ret)
    
    regex = re.compile('\s+\d+\s+')
    ret = regex.split(' ' + s)
    print(4,ret)
  • 分組使用小括號的pattern捕獲的數據被放到了組group中。
    • match、search函數可以返回match對象;findall返回字符串列表;finditer返回一個個match對象
    • 如果pattern中使用了分組,如果有匹配的結果,會在match對象中:使用group(N)方式返回對應分組,1-n是對應的分組,0返回整個匹配的字符串;如果使用了命名分組,可以使用group(‘name’)的方式取分組;也可以使用groups()返回所有命名的分組;使用groupdict()返回所有命名的分組組成的字典

練習

  • 匹配郵箱地址
    test@hot-mail.com
    v-ip@magedu.com
    web.manager@magedu.com
    super.user@gmail.com
    a@w-a-com
  • 匹配html標記內的內容
    <a href='http://www.baidu.com/index.html' target='_blank'>馬哥教育</a>
  • 匹配url
    http://www.baidu.com/index.html
    https://login.magedu.com
    file:///etx/syconf/newksa
  • 匹配二代身份證ID
  • 匹配密碼強弱
  • 單詞統計
1.

[\w-]+@[^\s-]+.com

\w+[-.\w]*@[\w-]+(\.[\w-]+)+

2.
<a href='(?<url>[^']+)' [^<>]+>\w+</a>

html提取
<[^<>]+>(.*)<[^<>]+>

匹配標記a
<(\w+)\s+{^<>}+>(.*)(</\1>)

3.
url提取
(\w+)://([^\s]+)

4.
\d{17}[0-9xX]|\d{15}

5.
^[a-zA-Z0-9_]{10,15}$

6. 單詞統計

import re
from collections import defaultdict

regex=re.compile(r'[^\w-]')

d = defaultdict(lambda : 0)
with open('d:/sample.txt',encoding='utf-8') as f:
    for line in f:
        for x in regex.split(line):
            if len(x) >= 1:
                d[x.lower()] += 1

# print(d)
print(sorted(d.items(),key= lambda x:x[1],reverse=True))
print(d['path1'],d['sub-path'])

def word_cnt(path:str):
    d = defaultdict(lambda :0)
    with open('d:/sample.txt',encoding='utf-8') as f:
        for line in f:
            for x in regex.split(line):
                if len(x) >= 1:
                    d[x.lower()] += 1
    return d
#print(word_cnt('d:/sample.txt'))

i = 0
for x in sorted(word_cnt('d:/sample.txt').items(),key = lambda x:x[1],reverse=True):
    if i < 10:
        print(x)
    i += 1
print(word_cnt('d:/sample.txt')['path1'],word_cnt('d:/sample.txt')['sub-path'])

  1. 1-9 ?

本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/88237

(0)
KX_ilKX_il
上一篇 2017-11-05
下一篇 2017-11-05

相關推薦

  • 電子眼find

     1、摩根定律。         話不多說,先上圖。          如圖:A和B交集為3    A = 4 + 3  &nbs…

    Linux干貨 2016-08-16
  • linux學習筆記: grep命令,正則表達式

    linux學習筆記:grep命令,正則表達式 linux運維筆記 簡介 grep命令是一個最初用于Unix操作系統的命令行工具,在給出文件列表或者標準輸入之后,grep會對匹配一個或者多個正則表達式的文本進行搜索,并且只輸出匹配或者不匹配的行或者文本。(參見維基百科)  正則表達式是計算機科學的一個概念,正則表達式使用單個字符串…

    Linux干貨 2017-04-07
  • 安全和加密與創建簽名證書

    安全和加密:NIST定義的安全屬性:(美國國家標準與技術研究院)保密性:        數據保密性        隱私性完整性:不可篡改        數據完整性        系統完整性高可用性: …

    Linux干貨 2017-04-11
  • 走進Linux(一)

    一、計算機基礎 世界上第一臺計算機于1946年誕生于美國賓夕法尼亞大學,名叫:ENIAC。     計算機主要由硬件系統和軟件系統兩部分組成:     1、組成硬件的五大部分:    控制器(Control):是整個計算機的中樞神經,其功能是對程序規定的控制信息進行解釋,根據其要求進行控制,調度程序…

    Linux干貨 2016-09-22
  • RAID簡述和Linux軟RAID配置

    RAID簡述和Linux軟RAID配置 PS:僅為課程練習,原理和配置可能有誤,僅供參考,謝謝; 1.RAID功能簡述     RAID,全稱(Redundant Arrays of Inexpensive Disk或Redundant Arrays of Independent Disk),現在一般多用于后面那個稱呼,獨立磁盤冗余陣列。RAID的基礎概念大…

    Linux干貨 2016-07-17
  • AB測試命令

    [root@chuangyuegou ~]# ab -n 10000 -c 49 http://192.168.0.99/index.html This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd,…

    Linux干貨 2016-12-05
欧美性久久久久