【问题标题】:match a String based on regex pattern matching scala匹配基于正则表达式模式匹配的字符串
【发布时间】:2019-03-16 18:22:38
【问题描述】:

我写了以下正则表达式:

val reg = ".+([A-Z_].+).(\\d{4})_(\\d{2})_(\\d{2})_(\\d{2})\\.orc".r 

应该解析以下字符串: “S3//bucket//TS11_YREDED.2018_09_28_02.orc” 解析方法是:

val dataExtraction: String => Map[String, String] = {
  string: String => {
    string match {
      case reg(filename, year, month, day) =>
                 Map(FILE_NAME-> filename, YEAR -> year, MONTH -> month, DAY -> day)
      case _  => Map(FILE_NAME-> filename,YEAR -> "", MONTH -> "", DAY -> "")
    }
  }
}
val YEAR = "YEAR"
val MONTH = "MONTH"
val DAY = "DAY"
val FILE_NAME = "FILE_NAME"

但它不能正常工作 它应该省略存储桶名称并解析文件名和日期

所以预期的输出应该是: Map(FILE_NAME-> TS11_YREDED, YEAR -> , MONTH -> 09, DAY -> 28) 知道如何解决它吗?

【问题讨论】:

    标签: regex scala pattern-matching


    【解决方案1】:

    .+ 模式部分首先匹配整个字符串,([A-Z_].+) 仅捕获后续模式需要捕获和匹配的内容。

    你可以使用

    """(?:.*/)?(.*)\.(\d{4})_(\d{2})_(\d{2})_\d{2}\.orc""".r
    

    this regex demo

    请注意,点必须转义以匹配文字点。

    详情

    • (?:.*/)? - 除换行符之外的任何 0+ 字符,尽可能多,直到最后一个 / 并包括它
    • (.*) - 捕获组 1:任何 0+ 字符,除了换行符,尽可能多
    • \. - 一个点
    • (\d{4}) - 捕获组 2:四位数字
    • _ - 下划线
    • (\d{2}) - 捕获组 3:两位数
    • _ - 下划线
    • (\d{2}) - 捕获组 4:两位数
    • _\d{2}\.orc - _,2 位数字,.orc 在字符串的末尾。

    Scala demo:

    val text = "S3//bucket//TS11_YREDED.2018_09_28_02.orc"
    val reg = """(?:.*/)?(.*)\.(\d{4})_(\d{2})_(\d{2})_\d{2}\.orc""".r
    
    var YEAR = "YEAR"
    var MONTH = "MONTH"
    var DAY = "DAY"
    var FILE_NAME = "FILE_NAME"
    
    val dataExtraction: String => Map[String, String] = {
      string: String => {
        string match {
          case reg(filename, year, month, day) =>
                     Map(FILE_NAME-> filename, YEAR -> year, MONTH -> month, DAY -> day)
          case _  => Map(FILE_NAME-> FILE_NAME,YEAR -> YEAR, MONTH -> MONTH, DAY -> DAY)
        }
      }
    }
    
    println(dataExtraction(text))
    // => Map(FILE_NAME -> TS11_YREDED, YEAR -> 2018, MONTH -> 09, DAY -> 28)
    

    由于您没有使用最后一个捕获组,因此可以将其从模式中省略。

    【讨论】:

    • 我会使用"""^([A-Z0-9_]+)\.(\d{4})_(\d{2})_(\d{2})_(\d{2})\.orc$""".r,以便它匹配整个输入(而不仅仅是其中的一部分),并考虑由大写、数字和下划线字符组成的FILE_NAME 字段。此外,如果要忽略最后一个数字,则不应在正则表达式中对其进行分组(改用"""^([A-Z0-9_]+)\.(\d{4})_(\d{2})_(\d{2})_\d{2}\.orc$""".r,并且不要在case 语句中将s 参数添加到reg
    • @MikeAllen val reg = """(.*?)\.(\d{4})_(\d{2})_(\d{2})_(\d{2})\.orc""".r 匹配整个字符串,它无法匹配任何部分文本,因为它用于匹配块中。 .unanchored 会使其找到部分匹配项。
    • 同意,但在正则表达式定义中明确表示没有害处。 :-) 顺便说一句,[A-Z_].+ 是错误的,除了您给出的原因之外:它不包括数字字符(在示例中出现),] 之后的句点确保范围内只有一个字符匹配, 后跟一个或多个其他字符 - 可以是任何字符。应删除句号。此外,OP 的原始代码有 5 个正则表达式组,但在 case 语句中只匹配其中的 4 个。
    • @MikeAllen 让 OP 询问他们需要澄清什么。我解释了如何使它工作。剩下的就是细节了。
    • @Wiktor,我更新了问题,你的正则表达式在这种情况下不起作用
    【解决方案2】:

    看看这个:

    val file_name = "TS11_YREDED.2018_09_28_02.orc"
    val reg = """(.*?)\.(\d{4})_(\d{2})_(\d{2})_(\d{2})\.orc""".r
    var file_details = scala.collection.mutable.ArrayBuffer[String]()
    reg.findAllIn(file_name).matchData.foreach( m => file_details.appendAll(m.subgroups))
    val names=Array("FILE_NAME","YEAR","MONTH","DAY","DUMMY")
    for( (x,y) <- names.zip(file_details).toMap)
      println(x + "->" + y)
    
    //DUMMY->02
    //DAY->28
    //FILE_NAME->TS11_YREDED
    //MONTH->09
    //YEAR->2018
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-14
      • 2019-04-05
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 2012-06-05
      • 2013-12-25
      相关资源
      最近更新 更多