Scala正则表达式中使用$(字符串结尾)

5

我有一些困难。(我擅长使用正则表达式,但在scala / java中并没有多少使用经验。)我有一个长度为11个字符的数字字符串,只需要最后10个字符,因此:

val Pattern = """(\d{10})$""".r
"79283767219" match {
  case Pattern(m) => m
}

它会产生“MatchError”,但为什么?我理解错了什么吗?

我的意思是,为什么它要尝试匹配整个字符串?它没有限制在行的开头。 - dmitry
好的,我从一开始就理解了“发生了什么”,我感兴趣的是如何使其正常工作,而不是匹配,例如如果有隐式的^和$。 - dmitry
3个回答

12

当您使用正则表达式模式进行匹配时,正则表达式模式应该与整个字符串匹配。也就是说,它就像正则表达式模式以^开头并以$结尾一样。这是因为match应该将左侧的整体分解到右侧。

在Scala 2.10中,可以调用unanchored来获取执行部分匹配的匹配器,如下所示:

val Pattern = """(\d{10})$""".r.unanchored

请放心,您的锚点将被保留。只是期望匹配应该适用于整个字符串的部分将被删除。


谢谢,丹尼尔!我不知道 unanchored。 我猜它在模式的 两端 添加了 .*? 我认为这对于原始问题无效。 它还可能与已经存在的 $ 产生不良互动。在某些 RE 方言中(现在太懒得检查),$ 仅在它是 RE 中最后一个字符时才是右侧锚定点。 unanchored 有多聪明? - Randall Schulz
1
@randall-shulz 我在2.10中进行了检查,它的工作方式符合预期。显式锚点的行为就像我认为它们应该从一开始就表现出来的那样。 - dmitry
这样也可以,但我认为最好按照它们的设计方式使用,作为完全匹配。两种方式并没有本质上的优劣之分。如果是搜索,你必须显式地锚定它。作为匹配,你必须显式地浮动它。就个人而言,我喜欢现在的方式。当我在Scala的match结构中使用RegEx时,我很少需要搜索。 - Randall Schulz
1
@RandallSchulz,未锚定的更改在执行unapplySeq时调用的方法,而不对模式本身进行任何更改。这可能会根据模式产生严重的性能提升。 - Daniel C. Sobral
@DanielC.Sobral:解除模式的锚定只会使匹配过程变得更长,就我所知。 - Randall Schulz
显示剩余4条评论

7
因为你有11个数字,而不是10个。您可以使用{10,}设置“ 10及以上”。要仅匹配字符串的结尾,您需要明确指定完整模式:
 val Pattern = """.*(\d{10})$""".r

更新:如果你使用的是Scala 2.10及以上版本,你可以使用Daniel的unanchored来解决这个问题。否则,你可以采用以下方法进行解决:

Pattern.findFirstIn("79283767219")

1
你能提供一个明确指定的链接吗?正则表达式理解 ^$ 符号,但它们似乎隐含在其中。这是不可避免的,还是有一些修改器或选项? - dmitry
1
@dmitry 只需使用 Pattern.findFirstIn("79283767219") - om-nom-nom
在我的情况下,这似乎是解决方案。把它加入答案中,好吗? - dmitry
2
@dmitry,文档中特别指定了 unapplySeq 方法。 - Daniel C. Sobral
请注意,即使使用 unanchoredfindFirstIn^ 字符仍然表示整个字符串的开头,而不是行的开头。因此,您需要像 (^|\n) 这样的东西来获取一行的开头(即字符串的开头或换行符)。 - combinatorist

3
请注意,当像您的示例中的Pattern这样的RegEx实例在match结构中使用时,它不是搜索,而是匹配!这意味着它必须匹配整个被匹配的值(在Scala术语中称为“scrutinee”-在您的示例中为79283767219)。
这就解释了为什么您的示例出现了MatchError

好的,那么,有没有什么方法可以避免这种情况?不需要重写正则表达式。也许不需要模式匹配。 - dmitry
不更改正则表达式吗?不行。必要时使用.*来浮动模式。 - Randall Schulz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接