如何理解 gsub(/^.*\//, '') 或正则表达式

3

为了理解我的正则表达式和gsub函数,将下面的代码拆开:

str = "abc/def/ghi.rb"
str = str.gsub(/^.*\//, '')
#str = ghi.rb

^ :表示字符串开头

\/ :是转义字符,用来转义 /

^.*\/ :从字符串开始到最后一个 / 之间的所有内容

我的理解正确吗?

.* 到底是如何工作的?


2
实际上,^ 是行首锚点。字符串开头是 \A。对于单行字符串,两者的作用相同。 - undur_gongor
2
你的正则表达式没有问题,但是File.basename(str)可能更合适。 - Stefan
这在互联网上和正则表达式文档中都有很好的记录。http://meta.stackoverflow.com/questions/261592/how-much-research-effort-is-expected-of-stack-overflow-users - the Tin Man
5个回答

4
您的理解是正确的。整个正则表达式将匹配abc/def/,并且String#gsub将用空字符串替换它。
然而,请注意String#gsub不会直接更改原始字符串。这意味着在替换后,str将包含原始值("abc/def/ghi.rb")。要直接更改原始字符串,您可以使用String#gsub!
至于.*如何工作 - 正则表达式引擎使用的算法称为回溯。由于.*是贪婪的(尝试尽可能多地匹配字符),您可以认为会发生以下情况: 步骤1: .*匹配整个字符串abc/def/ghi.rb。之后,\/尝试匹配一个斜杠,但失败了(没有剩余的内容可以匹配)。.*必须回溯。 步骤2: .*匹配除最后一个字符外的整个字符串 - abc/def/ghi.r。之后,\/尝试匹配一个斜杠,但失败了(/ != b)。.*必须回溯。 步骤3: .*匹配除最后两个字符外的整个字符串 - abc/def/ghi.。之后,\/尝试匹配一个斜杠,但失败了(/ != r)。.*必须回溯。 ... 步骤n: .*匹配abc/def。之后,\/尝试匹配一个斜杠并成功。匹配到此结束。

如果引用格式中的步骤来自另一个网站或个人,则重要的是给予他们适当的归属。如果它们不是从另一个网站或个人引用的,则使用引用是错误的格式。 - the Tin Man
@theTinMan,我经常看到引用被用于其他事情(比如长行的日志)。如果你有建议,让整个文本块看起来像是在不同的高亮状态下,同时又让我有粗体和代码内嵌的选项,那我会使用它。 - ndnenkov
即使是长日志也不应该被引用。人们使用它是因为它强制换行,而不是提取最少量的必要信息来演示问题,所以不要模仿那种想法。需要更改背景颜色吗?引用会显示它来自另一个来源。如果这是您的内容,则允许其成为正常背景,并使用编号列表的现有格式。这样,他们更改站点的CSS时,信息适合外观和感觉,而不是您认为它应该是的特定天。 - the Tin Man
@theTinMan,所以你没有提供其他选择。你必须明白,如果没有其他选择,人们会使用引用来实现实际目的。例如,如果这个答案全部在白色背景中,那么它将变得不太可读。有时候人们无法从他们的日志中提取关键信息,这就是他们提问的重点。难道日志永远不能用于问题中吗? - ndnenkov
有其他选择,只是人们不想相信那些方法可行。绝大部分网站使用非常简单的格式,而且效果很好。指南规定要将输入信息减少到最低限度,几乎每个日志都可以大大缩减以提供必要的信息。人们不去缩减更多地是因为他们不愿花费精力弄清楚什么是必要的。但这是一个不同的话题,经常在 [meta] 上讨论。 - the Tin Man

2

不完全正确。

  • ^:行首
  • \/:转义斜杠(转义字符为 \
  • ^.*\/:从行首到字符串中最后一个 / 的所有内容

.* 取决于正则表达式的模式。在单行模式下(即没有 m 选项),它表示零个或多个非换行符的最长可能序列。在多行模式下(即使用 m 选项),它表示零个或多个字符的最长可能序列。


1
你的理解是正确的,但你还应该注意到最后一句话是正确的,因为:
Repetition is greedy by default: as many occurrences as possible 
are matched while still allowing the overall match to succeed. 

引用自 Regexp 文档。

1
不要在锚文本中使用“这里”这样的无用词汇,尽量提供更有用的信息。请参阅http://www.w3.org/QA/Tips/noClickHere和http://www.w3.org/TR/WCAG10-HTML-TECHS/#link-text,了解详细原因。 - the Tin Man
@theTinMan 谢谢您的建议。我相信它很有用,我会尝试在我的未来帖子中遵循它。 - Ivaylo Strandjev

0
没有你的正则表达式有问题,但是File.basename(str)可能更合适。
为了阐述@Stefen所说的:看起来你正在处理文件路径,这使得你的问题成为一个XY问题,当你应该问X时你在问Y:与其如何使用和理解正则表达式,问题应该是什么工具用于管理路径。
不要自己编写代码,使用已经写好的随语言附带的代码即可。
str = "abc/def/ghi.rb"
File.basename(str) # => "ghi.rb"
File.dirname(str) # => "abc/def"
File.split(str) # => ["abc/def", "ghi.rb"]

你想利用文件内置代码的原因是它考虑了*nix风格操作系统和Windows之间目录分隔符的差异。在启动时,Ruby会检查操作系统并将File::SEPARATOR常量设置为操作系统所需的内容:
File::SEPARATOR # => "/"

如果您使用内置方法,代码从一个系统移动到另一个系统时将继续工作,而使用正则表达式将立即中断,因为分隔符将是错误的。

0

是的。简而言之,它匹配以字面意义的/\/)结尾的任意数量的任何字符(.*)。

gsub将匹配项替换为第二个参数(空字符串'')。


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