【Scala】Scala ~ 基本編 / 正規表現 ~

■ はじめに

Scala が慣れない、、、
今回は、Scala の 正規表現 (regular expression) について扱う。

正直、めちゃくちゃ、いまいち、、、
Javaの正規表現メソッド使った方がいいかも、、、

目次

【0】正規表現オブジェクト
 1)メソッド
【1】抽出
【2】置換
【3】Javaの正規表現を使う

【0】正規表現オブジェクト

* 生成の仕方は、以下の通り
* とりあえず、『その2:raw記法「"""」』でいいと思う

その1

val targetDate1 = "(\\d{4})-(\\d{2})-(\\d{2})".r
// 末尾のr は、正規化オブジェクト生成メソッド

その2:raw記法「"""」

// \でエスケープを省くことができる
val targetDate2 = """(\d{4})-(\d{2})-(\d{2})""".r

その3:raw補完子「raw」

// 効果はraw記法と同じ
val targetDate2 = raw"(\d{4})-(\d{2})-(\d{2})".r

1)メソッド

method Return value Explanation Memo
findFirstIn Option[String] パターンに一致する文字列を抽出 Optionで返すので、一致しなかったら「isDefined」で確認すればいい
findPrefixOf Option[String] 文の先頭がパターンに一致する文字列であれば抽出
findAllIn MatchIterator(イテレータ パターンに一致する文字列を全て抽出
findFirstMatchIn Option[Regex.Match] パターン中のグルーピングを抽出

https://takafumi-s.hatenablog.com/entry/2015/08/19/130513
https://www.scala-lang.org/api/2.13.4/scala/util/matching/Regex.html

【1】抽出

* コレクションの抽出には、filterが使える
 => 詳細は、以下の関連記事を参照のこと

Scala ~ 基本編 / コレクション ~
https://dk521123.hatenablog.com/entry/2023/03/13/000345

1)サンプル

例1:年月日を取得

val targetDate = raw"(\d{4})-(\d{2})-(\d{2})".r
val dates = "Important dates in history: 2004-01-20, 1958-09-05, 2010-10-06, 2011-07-15"
val firstDate = targetDate.findFirstIn(dates).getOrElse("No date found.")
val firstMonth = for (match <- targetDate.findFirstMatchIn(dates)) yield match.group(2)
println(firstMonth.get) // 01 (2004-<01>-20)

例2:ファイル名に付加されている日付を取得

import scala.util.matching.Regex

object Main extends App {
  val targetRegex: Regex = """\S+/user-\S+_(\d{8})_\S+\.csv""".r
  val targetS3File = "s3://your-bucket/hello/users/user-xxxxx_20230317_xxx.csv"
  val result = targetS3File match {
    case targetRegex(targetDate) => targetDate
    case _ => -1
  }
  println(s"Result: ${result}")
}

例3:s3のフルパスからS3バケット/S3キーを抽出

import scala.util.matching.Regex

object  Hello {
  def main(args: Array[String]) {
    val targetS3Path = "s3://your-s3-bucket/xxxx/yyyy/zzzzz/"
    val targetRegex: Regex = """s3://([^/]*)(\S+)""".r
    type URLParts = (String, String)
    val parts: URLParts = targetS3Path match {
      case targetRegex(s3BucketName, s3Key) => (s3BucketName, s3Key)
      case _ => ("", "")
    }
    val s3BucketName = parts._1
    val s3Key = parts._2
    println(s"Result: ${s3BucketName}    ${s3Key}") // Result: your-s3-bucket    /xxxx/yyyy/zzzzz/
    println("Done...")
  }
}

【2】置換

replaceメソッドなど、文字列を置換する方法を紹介|Scalapedia

1)サンプル

例1:ファイル名に付加されている日付を取得

val targetS3File = "s3://your-bucket/hello/users/user-xxxxx_20230317_xxx.csv"
// ファイル名だけ取得
val file = new java.io.File(targetS3File)
// 数字以外を全て削除する(荒業)
println(file.getName().replaceAll("[^\\d]+", ""))

【3】Java正規表現を使う

* 普通に使える。

1)サンプル

例1:ファイル名に付加されている日付を取得する

import java.util.regex.Matcher
import java.util.regex.Pattern

object Main extends App {
  val targetS3File = "user-xxxxx_20230317_xxx.csv"
  val pattern = Pattern.compile("user-\\S+_(\\d{8})_\\S+\\.csv")
  val matcher = pattern.matcher(targetS3File)
  if (matcher.find()){
    val date = matcher.group(1)
    println(s"${date}")
  } else {
    println("None...")
  }
}

参考文献

https://hkawabata.github.io/technical-note/note/Language/Scala/regular-expression.html
https://scala-lang.org/api/3.1.1/scala/util/matching/Regex.html
https://docs.scala-lang.org/tour/regular-expression-patterns.html

関連記事

Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / メソッド ~
https://dk521123.hatenablog.com/entry/2023/03/03/000000
Scala ~ 基本編 / クラス ~
https://dk521123.hatenablog.com/entry/2023/03/14/000857
Scala ~ 基本編 / コレクション ~
https://dk521123.hatenablog.com/entry/2023/03/13/000345
Scala ~ 基本編 / 日付・日時 ~
https://dk521123.hatenablog.com/entry/2023/03/08/000000
Scala ~ 基本編 / パターンマッチング ~
https://dk521123.hatenablog.com/entry/2023/06/06/233614
Scala ~ ファイル名・パスの扱い ~
https://dk521123.hatenablog.com/entry/2023/03/11/000000
ScalaYAML
https://dk521123.hatenablog.com/entry/2023/03/16/012034

Java

正規表現 ~ 一致・不一致の判定 ~
https://dk521123.hatenablog.com/entry/2014/06/10/224404
正規表現 ~ 文字列の抽出 ~
https://dk521123.hatenablog.com/entry/2016/12/30/142128
正規表現 ~ 数字/文字の出現回数を数える ~
https://dk521123.hatenablog.com/entry/2016/10/19/004224_1
正規表現 ~ 不要文字除去 / 対象文字のみ抽出 ~
https://dk521123.hatenablog.com/entry/2017/01/19/213612
正規表現 ~ 複雑な文字列置き換え ~
https://dk521123.hatenablog.com/entry/2015/04/08/000052

その他

正規表現 全般
https://dk521123.hatenablog.com/entry/2011/09/10/235712