Scala 正则表达式匹配具有特殊字符的行

Scala regex match lines with special characters

我有一个从文件中读取行的代码段,我想过滤掉某些行。基本上,我想过滤掉没有三个制表符分隔列的所有内容,其中第一列是数字,其他两列可以包含除制表符和换行符(Dos 和 Unix)之外的每个字符。

我已经在 http://www.regexr.com/ 上检查了我的正则表达式,它可以正常工作。

scala> val mystr = """123456\thttp://some.url/path/to/resource\t\x03U\x1D\x1F\x04D0B0@\xA0>\xA0<\x86:http://some.url/path/to/resource\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04C0A0?\n"""
scala> val myreg = "^[0-9]+(\t[^\t\r\n]+){2}(\n|\r\n)$"

scala> mystr.matches(myreg)
res2: Boolean = false

我发现问题与特殊字符有关。比如一个简单的例子:

scala> val tabstr = """123456\t123456"""
scala> val tabreg = "^[0-9]+\t[0-9]+$"
scala> tabstr.matches(tabreg)
res3: Boolean = false

scala> val tabstr = "123456\t123456"
scala> val tabreg = "^[0-9]+\t[0-9]+$"
scala> tabstr.matches(tabreg)
res4: Boolean = true

我的行似乎不能使用原始字符串(请参阅第一个代码块中的 mystr)。但是如果我不使用原始字符串,scala 会抱怨

error: invalid escape character

那么我该如何处理这些乱七八糟的输入并仍然使用我的正则表达式过滤掉一些行呢?

您正在使用原始字符串文字。在原始字符串文字中,\ 不用于转义制表符 \t 或换行符 \n 等序列,原始字符串文字中的 \n 只是两个字符。

在正则表达式中,要匹配文字 \,您需要在基于原始字符串文字的正则表达式中使用 2 个反斜杠,在常规字符串中使用 4 个反斜杠。

因此,要匹配您的所有输入,您需要使用以下正则表达式:

val mystr = """23456\thttp://some.url/path/to/resource\t\x03U\x1D\x1F\x04D0B0@\xA0>\xA0<\x86:http://some.url/path/to/resource\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04C0A0?\n"""
val myreg = """[0-9]+(?:\t(?:(?!\[trn]).)*){2}(?:\r)?(?:\n)"""
println(mystr.matches(myreg)) // => true
val tabstr = """123456\t123456"""
println(tabstr.matches("""[0-9]+\t[0-9]+""")) // => true
val tabstr2 = "123456\t123456"
println(tabstr2.matches("""^[0-9]+(?:\t|\t)[0-9]+$""")) // => true

非捕获组在这里并不重要,因为您只需要检查字符串是否为 matches(这意味着您甚至不需要 ^$因为整个输入字符串必须匹配)并且您仍然可以使用捕获组。如果您以后需要提取任何 matches/capturing 组,非捕获组将帮助您获得一个 "cleaner" 输出结构,就是这样。

最后两个正则表达式很简单,(?:\t|\t) 匹配 \+t 或制表符。 \t 只匹配一个制表符。

第一个有一个 tempered greedy token(这是一个简化的正则表达式,更好的可以与展开循环方法一起使用:[0-9]+(?:\t[^\]*(?:\(?![trn])[^\]*)*){2}(?:\r)?(?:\n))。

  • [0-9]+ - 1 个或多个数字
  • (?:\t(?:(?!\[trn]).)*){2} - 缓和的贪婪标记,出现 2 次文字字符串 \t 后跟除 2 符号组合 \t\r 以外的换行符以外的任何字符或 \n.
  • (?:\r)? - \r
  • 出现 1 次或 0 次
  • (?:\n) - \n.
  • 的文字组合出现一次