Splunkで使用できる正規表現のオプションについて

JSONなログから取り出す時`(?ms)`を使うようになってきたので、忘備録をかねて
Splunk公式は[ここ](https://docs.splunk.com/Documentation/Splunk/latest/Knowledge/AboutSplunkregularexpressions)
wikipediaは[ここ](https://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE)
[本家](https://www.pcre.org/original/doc/html/pcrepattern.html#SEC13)によるとオプションは

-  i  for PCRE_CASELESS
-  m  for PCRE_MULTILINE
-  s  for PCRE_DOTALL
-  x  for PCRE_EXTENDED

始めに`(?ms)`といった形で使う

##i
大文字と小文字を区別せずにマッチを行う

```java:caseless.spl
| makeresults 
| eval _raw="1584081083.114 ABC-12345,158 4081089.114 DEF-678910" 
| rex "(?i)(?<result>abc)"
```

|result|
|:-:|
|ABC|
ということで大文字・小文字関係なくマッチしてくれる。

##m
対象の文字列を複数行として扱う

##s
メタ文字(.)が改行にマッチ 

```java:multiline.spl
| makeresults 
| eval _raw="{\"studentInfo\": {
\"name\": \"Apple\",
\"id\": \"57\",
\"batch\": \"2006\",
\"subjects\": {
\"subject1\": \"English\"
}}}"
| rex "(?ms)subjects.*{.*\"(?<subjects>.*)\""
```
|result|
|:-:|
|English|

`(?m)`がないと正規表現は１行毎評価される。
正確には`^`と`$`が行頭・行末ではなく、文字列の最初と最後になる。

`(?s)`と一緒に使うと、行と関係なしにマッチングできる。
今回の`subjects.*{.*\"(?<subjects>.*)\"`で
`{.*\"`が途中の`\"`をすっ飛ばしているのが`Greedy`マッチングの特徴。
`{.*?\"`にすると最初の`\"`で止まってしまう。これは`Lazy`マッチング。

##x
パターンの中の空白やコメントを無視する

```java:extended.spl
| makeresults 
| eval _raw="{\"studentInfo\": {
\"name\": \"Apple\",
\"id\": \"57\",
\"batch\": \"2006\",
\"subjects\": {
\"subject1\": \"English\"
}}}"
| rex "(?msix)subjects.*{.*\"(?<subjects>e n g l i s h)\""
```
|result|
|:-:|
|English|

#その他

- J (PCRE_INFO_JCHANGED)
- x (PCRE_EXTENDED)
- U (PCRE_UNGREEDY)

cf. https://www.php.net/manual/ja/reference.pcre.pattern.modifiers.php
##J
サブパターンで重複した名前を使用できるようになります。
##x
エスケープするか 文字クラスの内部を除き、 パターンの空白文字は完全に無視されます。 文字クラスの外にあって、かつエスケープされていない # と次の改行文字の間の文字も無視されます。

```java:extend_pcre.spl
| makeresults
| eval _raw="test1 test2
test3"
| rex "(?Jx)(?<result>\w+)\s*(?<result>\w+)\s*(?<result>\w+)#this is comment#"
```

動作検証のためだけに作ったので、あまり意味はないです。
`(?J)`のオプションがないと同じサブパターン名は使えない。
`(?x)`のオプションをつけると、`#コメント#`が使える。

`(?J)`を指定すると、`rex`の`max_match`が効かなくなるようで注意が必要です。
##U
量指定子の「貪欲さ」が反転します。

```java:ungreedy.spl
| makeresults
| eval _raw="test1 test2
test3"
| rex "(?U)(?<result>\w+)"
```
|Uオプションあり|Uオプションなし|
|:-:|:-:|
|t|test1|
と反転している。

##(?P=NAME)
```python:malicious_email_search.spl
index=_internal | head 1 | fields _raw
| eval _raw="Hello someone@example.com

If you Are you interested in this site?　
<h2><a href=\"http://someMalicious.com/\">http://www.yourfavorate.example.com/</a></h2>
"
| rex max_match=0 "(?msix)          # 複数行でマッチさせるため盛り沢山
\w+@(?P<mail_domain>[\w.]+)\b       # メールアドレスのドメインを抽出
.*                                  # メール本文中の他の箇所
(?<malicious_site>(?P=mail_domain)) # メールアドレスのドメインを使って詐称している場合、キャプチャーしてくれるはず"
| search malicious_site=*
```

ものすごくコンセプト紹介のために作ってみた。

`(?P=NAME)`は`rex`でフィールド抽出したフィールド名(NAME)の中身で検索が可能

悪性メールだと、受信者へのメールアドレスへの返信を装い、リンク先に表示されているHPのドメインはメールドメインから生成しているものもある。
その場合、こんな感じたと検知が可能（じゃないかな〜 :sweat_smile: ）


##props.confにおけるLINE_BREAKERについて
[Splunk>Answers](https://answers.splunk.com/answers/812053/complex-line-breaking-configuration-help-needed.html)で回答する際、[Splunk Add-on Builder](https://splunkbase.splunk.com/app/2962/)で確認していたら、結果として

```javascript:props.conf
SHOULD_LINEMERGE = false
LINE_BREAKER = Line.*[\r\n]\[.*\]\*.*([\r\n])\[.*\]Line
```
になった。(間違えていたので修正)


この結果からすると、`LINE_BREAKER`は`(?msU)`のオプション自動的に設定されると考えるとわかりやすい。
####解説
行末でイベントを分けたかったので、`([\r\n])`を基準で考える
`*`を含む行は`\[.*\]\*.*`
`Line`を含む行は`\[.*\]Line`と`Line.*`
これを順番に並べたのが設定
Greedyマッチが反転しているので`?`がいらない　

:sweat:あっているかな

##オプションを解除する
https://answers.splunk.com/answers/814182/extract-data-from-a-txt-file.html
でえらい苦労してやってみてわかりました。

```bash:transforms.conf
[merge_csv]
 REGEX = (?-ms)(?<Agent_Name>\w.*)\s+(?<Canal>\d+)\s+?(?<Ramal>\d+)\s+?(?<Id_do_Logger>\d+)\s+?(?<Dia>[\d\/]+)\s+?(?<Chamadas>\d+)
 MV_ADD = true
```
コマンドの結果をそのまま取り込んで、行で分割しないところからフィールドを抽出している。
`(?-ms)`とすることで、無理やり行を認識させている。
:sweat:気付いたら２時間やっていた・・・




#オプションではないけど
 - コメント
`(?# コメントがかける)`

```java:(?#.spl
| makeresults
| eval _raw="some text (aaa(b(c1)(c2)d)e)(test) more text"
| rex max_match=0 "(?<match>\([^()]*\))(?# コメント)"
``` 
 - (?R)または(?1)(?2)<br>再帰的に一致する。ただ`max_match`オプションがあるので使い方がよくわからなかった。

 - 独占的`+`量識別子

```java:一致しない.spl
| makeresults
| eval _raw="some text (aaa(b(c1)(c2)d)e)(test) more text"
| rex  "\((?<match>.*+)\)(?# 一致しないよ)"
```
`?`と`?`をつけない挙動は理解していたけど、奥が深い
正規表現のコストってSPLだとあんまり気にしないけど`SEDCMD`で使う場合は気にする必要がある。

#まとめ
Splunkだと*props.conf*や*transforms.conf*、`rex`、`replace()`あと`regex`とか正規表現を使う場面が多々ある。
オプションを使うと結構簡単にマッチングできる時があるので、活用してみてください。

cf. https://regexone.com/