go 路径/文件路径:清理定义不是幂等的

xjreopfe  于 4个月前  发布在  Go
关注(0)|答案(8)|浏览(109)

请在提交问题之前回答以下问题。谢谢!

你在使用的 Go 版本是什么( go version )?

版本 1.9

这个问题是否在最新版本中重现?

是的

你正在使用什么操作系统和处理器架构( go env )?

Windows/amd64

问题

Clean 函数定义的算法有缺陷,而且没有忠实地实现。
特别是,定义有缺陷,因为幂等条件

Clean(Clean(x)) == Clean(x)

可能失败,如果 Separator 不是 '/' ,就像在 Windows 系统上一样。
实际上,根据算法文档,在 Windows 系统上 '/' 将不会被处理为 Separator ,直到最终转换为 Separator 。因此,应用 Clean 一次或两次(在第一个清理步骤结束时将 '/' 翻译为 Separator )可能会返回不同的结果,与幂等条件相矛盾。
此外,算法实现略有偏差于文档。实际上,每个满足

os.IsPathSeparator(c) == true

的字符都被处理为 Separator ,而不仅仅是 Separator ,如算法定义所述。在 Windows 系统上,这对两者都是如此:'\\''/'
请注意,如果 os.IsPathSeparator('/') 对所有可用实现都为真,则 '/' 始终被处理为 Separator 。因此,尽管算法定义和实现中有错误,幂等性仍然可以神奇地保留。

建议

我建议澄清算法文档并按照以下方式调整实现。

文档
  1. 将第一句话更改为
    Clean 返回一个与 path 通过纯粹的词汇处理等效的最短路径名。首先,它将任何斜杠替换为分隔符。然后,它将以下规则迭代应用,直到无法进行进一步处理:
  2. 将句子中的 slash 更改为 Separator
    返回的路径以斜杠结尾 ...
  3. 删除句子
    最后,任何出现的斜杠都被替换为分隔符。
实现
  1. 在第一行添加以下语句
    path = FromSlash(path)
  2. 将任何表达式(如 os.IsPathSeparator(x))更改为
    x == Separator
  3. 将最后一行更改为:
    return out.string()
b0zn9rqh

b0zn9rqh1#

请提供一个简短的程序,以演示此问题。谢谢...
2017年11月24日,09:55,larhun ***@***.***>写道:在提交问题之前,请回答以下问题。谢谢!您正在使用的Go版本是什么(go version)?1.9这个问题是否会在最新版本中重现?是您正在使用的操作系统和处理器架构是什么(go env)?Windows/amd64问题Clean函数定义的算法有缺陷,而且没有忠实地实现。特别是,定义有缺陷,因为如果Separator不是'/',则Clean(Clean(x)) == Clean(x)可能会失败,例如在Windows系统上。实际上,根据算法文档,在Windows系统上,'/'不会在最终转换为Separator之前被处理为Separator。因此,应用Clean一次或两次(在第一次清理步骤结束时将'/'转换为Separator)可能会返回不同的结果,与幂等条件相矛盾。此外,算法实现略有偏差。实际上,满足os.IsPathSeparator(c) == true的所有字符都被视为Separator处理,而不仅仅是Separator,如算法定义所述。在Windows系统上,这对两者都是正确的:'\'和'/'。请注意,如果os.IsPathSeparator('/')对于所有可用的实现都为真,那么'/'始终被处理为Separator。因此,尽管算法定义和实现存在错误,幂等性仍然可以得到保留。建议我提议澄清算法文档并按以下方式修改实现。文档更改第一句话为Clean通过纯粹的词汇处理返回与路径等效的最短路径名。首先,它将任何斜杠替换为Separator。然后,它迭代地应用以下规则,直到无法再进行进一步处理:将句子中的斜杠替换为Separator The returned path ends in a slash ...删除该句子最后,任何出现的斜杠都被替换为Separator。实现在第一行添加path = FromSlash(path)更改任何表达式,如os.IsPathSeparator(x)为x == Separator更改最后一行为:return out.string()——您收到此邮件是因为您订阅了此线程。直接回复此电子邮件,查看GitHub上的版本,或者静音该线程。

rn0zuynd

rn0zuynd2#

这个问题可以通过一个程序来证明,只有当 os.IsPathSeparator('/') 返回 false 时才会发生,而在我的 Windows 系统上从未发生过这种情况。
因此,为了证明算法定义是有缺陷的,提供了一个修改后的 path/filepath 包:github.com/larhun/filepath 是原始版本的副本,除了 Clean 函数中任何出现 os.IsPathSeparator 的地方都被替换为 IsPathSeparator,定义如下:

func IsPathSeparator(s byte) bool {
    return s == Separator
}

这个条件只对 Separator 成立,符合为 Clean 函数定义的算法。
然后,以下程序打印 false

package main

import(
    "fmt"
    "github.com/larhun/filepath"
)

func main(){
    p1:="/../../.."
    p2:=filepath.Clean(p1) // returns "\..\..\.."
    p3:=filepath.Clean(p2) // returns "\"
    fmt.Println(p2==p3)    // i.e. Clean(Clean(p1)) != Clean(p1)
}

对于幂等函数,预期值是 true

7gcisfzg

7gcisfzg3#

我是否理解正确,您的意思是问题只在满足某个条件时发生,但这个条件不可能发生?

zf2sa74q

zf2sa74q4#

不,我并不是这么说的。问题在于文档和实现之间的错误和不一致。
文档中写道:
Clean通过纯粹的词汇处理返回与path等效的最短路径名。它会迭代地应用以下规则,直到无法再进行进一步处理:

1. Replace multiple Separator elements with a single one.
2. Eliminate each . path name element (the current directory).
3. Eliminate each inner .. path name element (the parent directory)
   along with the non-.. element that precedes it.
4. Eliminate .. elements that begin a rooted path:
   that is, replace "/.." by "/" at the beginning of a path,
   assuming Separator is '/'.

返回的路径以斜杠结尾,仅当它表示根目录,例如Unix上的"/"或Windows上的 C:\
最后,任何出现的斜杠都被Separator替换。
如果这个过程的结果是一个空字符串,Clean返回字符串"."。
我说的是之前的算法是错误的,因为它表示在最终替换任何斜杠出现之前,只处理 Separator 。如果这个算法精确地实现了,那么在Windows系统上, Clean 函数将不能是幂等的,如提供的程序所示。
然而,实现偏离了文档,并像 Separator 一样处理对 os.IsPathSeparator 为真的任何字符。在Windows系统上,这包括斜杠。然后,神奇地, Clean 函数结果变得幂等,尽管算法错误且实现错误。
文档不应该误导人。正确的算法应该首先用 Separator 替换斜杠。正确的实现应该按照算法所述执行。

06odsfpq

06odsfpq5#

如果实施有缺陷,如所声称的那样,必须有一种方法来证明与该缺陷实施相关的问题。但早些时候你写道:
问题只能通过程序来演示,如果os.IsPathSeparator('/')返回false,这在我的Windows系统上从未发生过。
os.IsPathSeparator('/')是否在其他系统中返回false?因为如果没有这样的系统,那么我们就有一些相互矛盾的信息。

31moq8wy

31moq8wy6#

为了澄清我之前的笔记,有两个错误会导致正确的行为。

  • 第一个错误是算法的定义,它在形式上不能保证预期的行为,如提供的程序所示。
  • 第二个是实现,它与所陈述的算法不同,但最终实现了预期的结果。

因此,

  • 为了算法文档的清晰度和质量,应该更改定义。
  • 实现不正确,但只要 os.IsPathSeparator 没有为斜杠返回 false 的新系统实现,它就可以正常工作。为了源代码的质量,应该进行更改。

我建议同时进行这两个更改。

bvk5enib

bvk5enib7#

对这个包的任何更改都可能影响数百万导入它的用户。正确的行为应该是引起最少惊讶的行为,并遵循兼容性指南。
更改算法所涉及的风险是新算法将不正确(并且这种不正确性也将是不一致的)。文件路径处理很微妙,需要许多特殊情况才能正确处理。这可能是代码现在看起来的样子的原因。
在一个'/'不是分隔符的系统中,正确性又从何谈起呢?

sulc1iza

sulc1iza8#

我认为没有必要更改实现。如果你认为我们应该更改文档,请务必发送一个pull请求。谢谢。

相关问题