整个列上的 Scala 正则表达式

Scala regex on a whole column

我可以使用 Python 中的 pandas 解析以下模式,但很难将代码转换为 Scala。

grade string_column    
 85   (str:ann smith,14)(str:frank chase,15)
 86   (str:john foo,15)(str:al more,14)

在python中我使用了:

df.set_index('grade')['string_column']\
.str.extractall(r'\((str:[^,]+),(\d+)\)')\
.droplevel(1)

输出:

 grade       0                1
 85      str:ann smith       14
 85      str:frank chase     15
 86      str:john foo        15
 86      str:al more         14

在 Scala 中,我尝试复制该方法,但失败了:

import scala.util.matching.Regex

val pattern = new Regex("((str:[^,]+),(\d+)\)")
val str = "(str:ann smith,14)(str:frank chase,15)"

println(pattern findAllIn(str)).mkString(","))

关于代码有几点说明:

  • 组中有一个不匹配的括号,但应转义该括号
  • 反斜杠应该双重转义
  • println 中,您不必使用所有括号和点
  • findAllIn returns 一个 MatchIterator,循环这些将公开匹配的字符串。用逗号连接那些匹配的字符串,在这种情况下将再次返回相同的字符串。

例如

import scala.util.matching.Regex

val pattern = new Regex("\((str:[^,]+),(\d+)\)")
val str = "(str:ann smith,14)(str:frank chase,15)"

println(pattern findAllIn str mkString ",")

输出

(str:ann smith,14),(str:frank chase,15)

但是如果你想打印出第 1 组和第 2 组的值,你可以使用 findAllMatchIn 那个 returns 正则表达式匹配的集合:

import scala.util.matching.Regex

val pattern = new Regex("\((str:[^,]+),(\d+)\)")
val str = "(str:ann smith,14)(str:frank chase,15)"
pattern findAllMatchIn str foreach(m => {
    println(m.group(1))
    println(m.group(2))
  }
)

输出

str:ann smith
14
str:frank chase
15

在Python中,Series.str.extractall仅returns捕获子字符串。在 Scala 中,findAllIn returns 匹配的值如果你不查询它的 matchData 属性 而它又包含一个 subgroups 属性.

因此,要仅在 Scala 中获取捕获,您需要使用

val pattern = """\((str:[^,()]+),(\d+)\)""".r
val str = "(str:ann smith,14)(str:frank chase,15)"
(pattern findAllIn str).matchData foreach {
    m => println(m.subgroups.mkString(","))
}

输出:

str:ann smith,14
str:frank chase,15

参见Scala online demo

此处,m.subgroups 访问每个匹配项 (m) 的所有子组(捕获)。

此外,请注意您不需要在三重引号字符串文字中使用双反斜杠。 \((str:[^,()]+),(\d+)\) 场比赛

  • \( - 一个 ( 字符
  • (str:[^,()]+) - 第 1 组:str:,()
  • 以外的一个或多个字符
  • , - 逗号
  • (\d+) - 第 2 组:一个或多个数字
  • \) - 一个 ) 字符。

如果你只是想得到所有匹配而不捕获,你可以使用

val pattern = """\((str:[^,]+),(\d+)\)""".r
println((pattern findAllIn str).matchData.mkString(","))

输出:

(str:ann smith,14),(str:frank chase,15)

参见online demo