【问题标题】:How to best combine Regex groups and streams to search a file如何最好地结合正则表达式组和流来搜索文件
【发布时间】:2016-11-15 12:56:26
【问题描述】:

我想扫描一个文件,只找到一个正则表达式的第一个实例,然后返回与该表达式匹配的组的值。

到目前为止,我的所有尝试似乎都非常笨拙,并且涉及重复使用正则表达式,一次是查找目标字符串,然后是再次获取组。我也不喜欢在 Regexp 的开头和结尾使用 .*。

任何人都可以提出一种更优雅的方式来做到这一点。

  val DateRegexp = """.*(\d\d\d\d)-(\d\d)-(\d\d).*""".r
  val lineWithDate = scala.io.Source.fromFile(filenameGC).getLines().find{_.matches(""".*(\d\d\d\d)-(\d\d)-(\d\d).*""")  }
  lineWithDate match {
    case Some(result) =>
       result match {
        case DateRegexp(year, month, day) =>
          println(year, month, day)
       }
    case None =>
      println("No date found in file")
  }

在得到 Cyrille Corpet 的大力支持后,我现在...

val DateRegexp = """(\d\d\d\d)-(\d\d)-(\d\d)""".r.unanchored
scala.io.Source.fromFile(filenameGC).getLines().collectFirst{
                   case DateRegexp(y, m, d) => println(y, m, d)}

【问题讨论】:

    标签: regex scala stream


    【解决方案1】:

    Regex 已经是一个模式(在模式匹配的意义上),所以你可以直接在你的case 语句中使用它:

    fileString match {
      case DateRegexp(year, month, day) => println(year, month, day)
    }
    

    但是,在您的情况下,.* 是贪婪的,它会捕获字符串中模式的最后一次出现。

    谢天谢地,如果您将其指定为 unanchored,您可以在模式的开头和结尾删除 .*(这意味着它不会尝试将模式与您的整个字符串匹配)。没有贪婪的*,你现在可以捕捉到第一个出现:

    val regex = """(\d\d\d\d)-(\d\d)-(\d\d)""".r.unanchored
    
    "1987-05-18 2002-12-14" match {
      case regex(y, m, d) => (y.toInt, m.toInt, d.toInt) // (1987, 5, 18)
    }
    

    编辑:我意识到我没有解决问题的第一个问题,即您没有String,而是Seq[String]。但是,一旦您拥有一行的提取器,您只需在所有行上使用它,直到第一个与 collectFirst 相关的行,它会找到与给定 cases 匹配的第一个匹配项并使用它:

    (lines: List[String]).collectFirst{
      case regex(y, m, d) => println(y, m, d)
    }
    

    【讨论】:

    • 不客气。在开始回答您的问题之前,我不知道unanchored,所以我很高兴发现这一点。
    猜你喜欢
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多