【问题标题】:How to understand gsub(/^.*\//, '') or the regex如何理解 gsub(/^.*\//, '') 或正则表达式
【发布时间】:2015-12-21 11:50:23
【问题描述】:

分解下面的代码来理解我的正则表达式和gsub的理解:

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

^:字符串的开头

\/ : / 的转义字符

^.*\/ :字符串中从/ 开始到最后出现的所有内容

我对表达的理解对吗?

.* 究竟是如何工作的?

【问题讨论】:

  • 实际上,^ 是行首的锚点。字符串的开头是\A。对于单行字符串,两者的工作方式相同。
  • 您的正则表达式没有问题,但File.basename(str) 可能更合适。
  • 这在 Internet 和 Regexp 文档中都有很好的记录。 meta.stackoverflow.com/questions/261592/…

标签: ruby regex gsub


【解决方案1】:

您的一般理解是正确的。整个正则表达式将匹配abc/def/String#gsub 将用空字符串替换它。

但是,请注意String#gsub 不会更改字符串。这意味着str 将包含替换后的原始值("abc/def/ghi.rb")。要更改它,您可以使用String#gsub!


至于.* 的工作原理——正则表达式引擎使用的算法称为backtracking。由于.* 是贪心的(会尝试匹配尽可能多的字符),你可以认为会发生这样的事情:

第 1 步.* 匹配整个字符串 abc/def/ghi.rb。之后\/ 尝试匹配正斜杠,但失败了(没有任何东西可以匹配)。 .* 必须回溯。
第 2 步.* 匹配除最后一个字符之外的整个字符串 - abc/def/ghi.r。之后\/ 尝试匹配正斜杠,但失败了 (/ != b)。 .* 必须回溯。
第 3 步.* 匹配除最后两个字符之外的整个字符串 - abc/def/ghi.。之后\/ 尝试匹配正斜杠,但失败了 (/ != r)。 .* 必须回溯。
...
第 n 步.* 匹配 abc/def。之后\/ 尝试匹配正斜杠并成功。匹配到此结束。

【讨论】:

  • 如果引用格式中的步骤来自其他网站或个人,请务必注明它们的正确归属。如果它们不是从其他人或人那里引用的,那么使用引用是错误的格式。
  • @theTinMan,我看到引用经常用于其他事情(如长行日志)。如果您对整个文本块如何看起来好像处于不同的突出显示状态有建议,同时让我可以选择 boldcode 在里面,我会使用它。
  • 即使是长日志也不应该被引用。人们使用它是因为它强制包装,而不是提取证明问题所需的最低限度,所以不要模仿这种想法。是否需要更改背景颜色?引用这样做是为了表明它来自另一个来源。如果它是您的内容,则允许它成为普通背景并使用现有格式作为编号列表。这样一来,他们更改网站的 CSS 时,信息会符合外观,而不是您认为的特定日期。
  • @theTinMan,所以您别无选择。您必须了解,如果没有其他选择,人们会将引用用于实际目的。例如,如果这个答案都是白色背景,那么它的可读性就会大大降低。有时人们无法在他们的日志中提取基本信息,这就是他们的问题的重点。日志不应该用在提问中吗?
  • 有替代品,只是人们不想相信那些工作。绝大多数网站都使用非常简单的格式,并且效果很好。该指南指定将输入信息减少到必要的最低限度,并且几乎每个日志都可以大大减少以提供必要的信息。人们不减少更多是他们不想花费精力来弄清楚什么是必要的例子。但这是 Meta Stack Overflow 上经常讨论的另一个话题。
【解决方案2】:

不,不完全是。

  • ^:行首
  • \/:转义斜线(转义字符为 \ 单独)
  • ^.*\/ :从行首到字符串中 / 最后出现的所有内容

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

【讨论】:

    【解决方案3】:

    你的理解是正确的,但你也应该注意最后一句话是正确的,因为:

    Repetition is greedy by default: as many occurrences as possible 
    are matched while still allowing the overall match to succeed. 
    

    引自Regexp 文档。

    【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      您的正则表达式没有问题,但 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"]
      

      您想利用 File 的内置代码的原因是它考虑了 *nix 风格操作系统和 Windows 中目录分隔符之间的差异。在启动时,Ruby 检查操作系统并将File::SEPARATOR 常量设置为操作系统需要的值:

      File::SEPARATOR # => "/"
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多