OCaml"字符串列表"的最长前缀,以特定的"字符串"值结尾



我正试图弄清楚,在特定元素最后出现后,是否有一种特别简洁或有效的方法来截断字符串。出于我的目的,它是一个单体化的string list,我正在寻找的string在编译时是已知的,因为我只在一种情况下使用它。

这样做的动机是在CWD的Unix目录系统中找到最近的祖先,其父目录中的名称是一个特定的文件夹名称。也就是说,如果我想找到最近的祖先bin,并且我正在从/home/anon/bin/projects/sample/src/bin/foo/的CWD运行可执行文件,那么我会想取回/home/anon/bin/projects/sample/src/bin

我目前使用的实现方式如下:

let reverse_prune : tgt:string -> string -> string =
let rec drop_until x ys =
match ys with
| [] -> []
| y :: _ when x = y -> ys
| _ :: yt -> drop_until x yt
in
fun ~tgt path ->
String.split_on_char '/' path
|> List.rev |> drop_until tgt |> List.rev |> String.concat "/"

这不是一个特别常见或昂贵的代码路径,因此实际上没有优化的必要,但由于我仍在尝试学习实用的OCaml技术,我想知道是否有更干净的方法来做到这一点。

我也意识到,从技术上讲,完全避免字符串拆分,只对原始CWD字符串进行操作而不进行拆分是可能的。当然,我也欢迎这样的建议,但我特别好奇是否有什么东西可以取代List.rev |> drop_until tgt |> List.rev片段,而不是以不同的方式解决整个问题。

我认为这实际上与OCaml无关,因为我认为最简单的方法是使用正则表达式:

let reverse_prune tgt path =
let re =
Str.regexp (Format.sprintf {|^[/a-zA-Z_-]*/%s([/a-zA-Z_-]*)$|} tgt)
in
Str.replace_first re {|1|} path
let () =
reverse_prune "bin" "/home/anon/bin/projects/sample/src/bin/foo/"
|> Format.printf "%s@."

您想在字符串中重新实现正则表达式搜索的原因是什么?如果没有,我会说,就用一个像我这样的解决方案。


如果您想要之前的零件,只需更改组:

let reverse_prune tgt path =
let re =
Str.regexp (Format.sprintf {|^([/a-zA-Z_-]*/)%s[/a-zA-Z_-]*$|} tgt)
in
Str.replace_first re {|1|} path

最新更新