# TLCL 輪読会 ### 19 – Regular Expressions 2023/03/28 [@kdnakt](https://twitter.com/kdnakt) --- ## 今日の範囲 ### 19 – Regular Expressions - grep - Metacharacters and Literals - The Any Character - Anchors - Bracket Expressions and Character Classes - POSIX Basic vs. Extended Regular Expressions - Alternation - Quantifiers - Putting Regular Expressions to Work --- ### 正規表現とは - テキスト中のパターンを見つけるための記法 - シェルのワイルドカードと類似 - 多くのコマンドや言語がサポート - バリエーションがある - 以下、POSIX標準を中心に進める --- ### grep (p.251~) - Global Regular Expression Printに由来 - 正規表現にマッチするテキストを検索 - マッチした行を出力 ```shell $ ls /usr/bin | grep zip ``` ---- #### grepのオプション (1) ```shell $ grep [options] regex [file...] ``` - -i,--ignore-case - 大文字小文字無視 - -v,--invert-match - 反転マッチ - -c,--count - マッチした行数を出力 ---- #### grepのオプション (2) - -l,--files-with-matches - マッチした行を含むファイル名を出力 - -L,--files-without-matches - マッチしない行を含むファイル名を出力 - -n,--line-number - 行番号を出力 - -h,--no-filename - 複数ファイル検索でファイル名非表示 ---- #### grep練習 ```shell # 準備 $ ls /bin > dirlist-bin.txt $ ls /usr/bin > dirlist-usr-bin.txt $ ls /sbin > dirlist-sbin.txt $ ls /usr/sbin > dirlist-usr-sbin.txt # 実践 $ grep bzip dirlist*.txt $ grep -l bzip dirlist*.txt $ grep -L bzip dirlist*.txt ``` --- ### Metacharacters and Literals (p.253~) - リテラル - 文字自身にマッチする - 例) `bzip` - メタ文字 - 複雑なマッチを実現する - `^ $ . [ ] { } - ? * + ( ) | \` - バックスラッシュ(\\)でエスケープ - 例) `\$` ---- #### 正規表現のメタ文字とシェル - メタ文字の多くはシェルでも特殊な意味 ```shell $ echo {a..c} a b c $ a="b" $ echo $a b $ a=(1 2 3) $ echo ${a[@]} 1 2 3 ``` - コマンドラインでのメタ文字を含む正規表現 -> 引用符必須 --- ### The Any Character (p.254~) - .(ドット): 任意の1文字にマッチ ```shell $ grep -h '.zip' dirlist*.txt bunzip2 bzip2 gunzip gzip (略) ``` - 注) `zip`は検索結果に出ない --- ### Anchors (p.255~) - キャレット(^): 行の先頭 - ドル記号($): 行の終端 ```shell $ grep -h '^zip' dirlist*.txt zip zipgrep (略) $ grep -h 'zip$' dirlist*.txt gunzip gzip (略) $ grep -h '^zip$' dirlist*.txt zip ``` ---- #### A Crossword Puzzle Helper - 5文字の単語 - 3文字目がj - 最後がr? ```shell $ grep -i '^..j.r$' /usr/share/dict/words Major major ``` --- ### Bracket Expressions and Character Classes (p.256~) - `[ ]`: マッチする文字の組を指定 ```shell $ grep -h '[bg]zip' dirlist*.txt bzip bzip2recover gzip ``` - `[ ]`内のメタ文字は普通の文字扱い - 例外は`^`(否定)と`-`(範囲指定) ---- #### Negation - `[^bg]zip`: bまたはg以外の文字+zip - zipの前に文字が来る必要がある - zipはマッチしない - `[ ]`内の先頭でのみ`^`は否定の意味となる - 他の位置の場合は文字の組の1つ ---- #### Traditional Character Ranges (1) - 大文字アルファベット始まりのファイル名を探す - :no_good: `grep -h '^[ABCDEFGHIJKLMNOPQRSTUVWXYZ]' dirlist*.txt` - :ok_woman: `grep -h '^[A-Z]' dirlist*.txt` ---- #### Traditional Character Ranges (2) - アルファベットまたは数字始まりのファイル名を探す - `grep -h '^[A-Za-z0-9]' dirlist*.txt` - ダッシュ(-)またはAまたはZを含む - `grep -h '[-AZ]' dirlist*.txt` ---- #### POSIX Character Classes - 次のような結果になるOSもある ```shell $ ls /usr/sbin/[A-Z]* /usr/sbin/biosdecode /usr/sbin/chat (略) ``` - 照合順序collation orderの差異 - ASCII: `ABC..Zabc...z` - 辞書: `aAbBcC...zZ` - 上の例は辞書順 - なのでa始まりの結果がない ---- ##### 文字クラス (1/2) | 文字クラス | 詳細 | |---------|---| | [:alnum:] | [A-Za-z0-9] | | [:word:] | [:alnum:] と `_` | | [:alpha:] | [A-Za-z] | | [:blank:] | スペースとタブ文字 | | [:cntrl:] | アスキーコードの0-31と127 | | [:digit:] | [0-9] | ---- ##### 文字クラス (2/2) | 文字クラス | 詳細 | |---------|---| | [:graph:] | アスキーコードの33-126 | | [:lower:] | [a-z] | | [:punct:] | -!"#$%&'()*+,./:;<=>?@[\\]_`{\|}~ | | [:print:] | [:graph:] + スペース | | [:space:] | [ \t\r\n\v\f] | | [:upper:] | [A-Z] | | [:xdigit:] | [0-9A-Fa-f] | ---- ##### 文字クラスの利用方法 ```shell $ ls /usr/sbin/[[:upper:]]* /usr/sbin/MAKEFLOPPIES /usr/sbin/NetworkManagerDispatcher /usr/sbin/NetworkManager ``` ---- #### Reverting to Traditional Collation Order - 照合順序: LANG環境変数で制御可能 ```shell # LANGは言語と文字コードからなる $ echo $LANG en_US.UTF-8 # 伝統的照合順序(ASCII)を利用したい場合 $ export LANG=POSIX # 文字コードがASCIIになるので注意 ``` --- ### POSIX Basic vs Extended Regular Expressions (p.262~) - POSIXにも2種類の正規表現 - BRE: Basic Regular Expressions - ERE: Extended Regular Expressions ---- #### BREとERE - 違いはメタ文字 - BRE: `^ $ . [ ] *` - ERE: BRE + `( ) { } ? + |` - 注) `( ) { }`はバックスラッシュでエスケープするとBREでもメタ文字扱い - egrep: EREをデフォルトにしたgrep - `grep -E`と同じ ---- #### POSIX - 1980年代、Unixが商用OSとして人気に - 個々のベンダが差別化を図る - IEEEがPOSIXとして標準化 - Portable Operating System Interface - 語感を良くするためXがついた --- ### Alternation (p.263~) - 拡張正規表現の機能のひとつ - `|`で表す。論理和(or) ```shell $ echo "AAA" | grep -E 'AAA|BBB|CCC' AAA $ echo "BBB" | grep -E 'AAA|BBB|CCC' BBB $ echo "DDD" | grep -E 'AAA|BBB|CCC' $ ``` --- ### Quantifiers - EREで特定の回数、文字にマッチさせる方法 - ?: 0回または1回 - *: 0回以上 - +: 1回以上 - {}: 指定回数以上 ---- #### 電話番号のカッコ有無 - 有効な電話番号 - (nnn) nnn-nnnn - nnn nnn-nnnn ```shell $ grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$' ``` - `()`の有無を`?`で判定 ---- #### 大文字で始まる文章 - OK: This works. - NG: this does not works ```shell $ grep -E '[[:upper:]][[:upper:][:lower:] ]*\.' ``` - [:upper:]または[:lower:]または半角スペース、が0回以上 ---- #### アルファベットと半角スペース1個のみの文字列 - OK - This is it - a b c - NG - a b 9 - abc d ```shell $ grep -E '^([[:alpha:]]+ ?)+$' ``` ---- #### 指定回数マッチさせる | 指定子 | 意味 | |-------|-----| | {n} | 直前の文字がちょうどn回 | | {n,m} | 直前の文字がn回以上m回以下 | | {n,} | 直前の文字がn回以上 | | {,m} | 直前の文字がm回以下 | - 手元のMacのzshでは{,m}は動かず... ```shell # 電話番号マッチの改良版 $ grep -E `^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$` ``` --- ### Putting Regular Expressions to Work - 以下、実践編 - grep - find - locate - less & vim ---- #### Validating a Phone List With grep ```shell # ランダムな電話番号リストを作成 $ for i in {1..10}; do echo "(${RANDOM:0:3}) ${RANDOM:0:3}-${RANDOM:0:4}" >> phonelist.txt; done # -vオプションでマッチしない無効な電話番号を抽出 $ grep -Ev `^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$` phonelist.txt (292) 108-518 (129) 44-1379 ``` ---- #### Finding Ugly Filenames with find - grep: 文字列の一部がマッチしたら結果出力 - find: 完全一致した場合に結果出力 ```shell # スペースやその他の有害な文字を含むパスを見つける # パス全体にマッチする必要があるので、前後に`.*` $ find . -regex '.*[^-_./0-9a-zA-Z].*' ``` ---- #### Searching for File with locate - locateコマンド - --regexpオプション: BRE - --regexオプション: ERE ```shell $ locate --regex 'bin/(bz|gz|gip)' /bin/bzcat /bin/bzcmp /bin/bzdiff (略) /bin/gzip /usr/bin/zip ``` ---- #### Searching for Text with less and vim - /キー+正規表現で検索可能 - less: EREをサポート - vim: BREをサポート - 量指定子はエスケープ必要 --- ### Summing Up - 正規表現の利用方法を少し学んだ - コマンドごとの使い方はman pageをzgrep ```shell $ cd /usr/share/man/man1 $ zgrep -El 'regex|regular exp' *.gz ```
{"metaMigratedAt":"2023-06-17T23:46:29.821Z","metaMigratedFrom":"YAML","title":"TLCL 輪読会","breaks":false,"slideOptions":"{\"transition\":\"slide\"}","description":"2023/03/28 @kdnakt","contributors":"[{\"id\":\"df36d0f0-b67e-41ac-96b3-f3988326d230\",\"add\":6975,\"del\":395}]"}
    529 views