regex 在VS代码脚本中将路径转换为命名空间

lnvxswe2  于 2023-10-22  发布在  其他
关注(0)|答案(2)|浏览(152)

我正在尝试创建一个VS代码片段,该代码片段基于项目中的当前文件夹构建名称空间。
TM_DIRECTORY变量提供的当前路径可能是这样的。
/Users/bernhardrichter/GitHub/heatkeeper2000/src/HeatKeeper.Server/Mapping
我希望最终得到的是namespace HeatKeeper.Server.Mapping,因为我的根源文件夹是src
所以我需要去掉之前的所有东西,包括src,这样我们就剩下HeatKeeper.Server/Mapping了。然后我需要将/替换(转换)为.,以便最终结果为HeatKeeper.Server.Mapping
有没有可能在一次转换中做到这一点?如果没有,是否可以有多个转换?
这是我目前所拥有的
"namespace ${TM_DIRECTORY/(.*src.)(.*).*$/$2/}"
这输出namespace HeatKeeper.Server/Mapping这几乎是我想要的。我只需要将所有/替换为.
问题是我不知道把这个转换放在哪里。
转换看起来像这样。
"${TM_DIRECTORY/[\\/]/./g}"
这给了我
.Users.bernhardrichter.GitHub.heatkeeper2000.src.HeatKeeper.Server.Mapping
我就是不知道怎么把这两个合并结合起来?

prdp8dxp

prdp8dxp1#

请在编辑后查看更一般的答案(不仅仅是最后两个目录)。
原文回答:
是的,你可以在一个片段中完成它们,你只需要分别捕获src之后的两个目录。试试看:

"namespace ${TM_DIRECTORY/.*src\\/(.*)\\/(.*)$/$1.$2/}",

然后在两个捕获组之间放置period。这个正则表达式假设您总是在所需的两个目录之前有一个src目录。如果不是这样,这将捕获最后两个目录:

"namespace ${TM_DIRECTORY/.*\\/(.*)\\/(.*)$/$1.$2/}",

注意路径分隔符“/“必须是双转义的。

**编辑-----------------------------------------------

对于更一般的情况,即在特定目录之后有未知数量的目录,请尝试以下形式:

"body": "${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g}",

// here for easier testing using the clipboard
"body": "${CLIPBOARD/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g}",

在出现src的地方,放入最后一个你不需要的目录。这适用于src之后的一个或多个目录(在本例中)。
有趣的是,这是一个文件夹的情况下,是最棘手的。这是通过额外的条件${3:+.}解决的,这意味着如果有捕获组3,则插入.
有关正则表达式的解释,请参见reg101 demo。在该链接中,您可以看到除了one folder case之外,还有一个更简单的替换。如果你不介意在最后一个.上回退,你可以用$2.$5代替我上面使用的$2${3:+.}${5:+.}$5
最后,请注意,上面的设计是为了使用正斜杠/路径分隔符。要修改它以使用反斜杠/正斜杠分隔符,请查看以下内容(将USERS作为最后一个不需要的目录):

"body": "${TM_DIRECTORY/.*Users[\\/\\\\](([^\\/\\\\]*)([\\/\\\\])?)|([\\/\\\\])([^\\/\\\\]*)/$2${3:+.}${5:+.}$5/g}",

所有的正斜杠\\/都被转换为正斜杠和反斜杠[\\/\\\\],如果你想测试文本\,反斜杠必须显示为\\\\。哟。
[For原来的问题,只需要在开头加上namespace

krugob8w

krugob8w2#

可悲的是@Marks解决方案并没有真正为我工作,它仍然包含驱动器和所有文件夹,直到文件名,或者如果我使用新的${RELATIVE_FILEPATH},它仍然包含文件名(我想要没有工作区文件夹的完整路径,所以基本上是一个c#项目中的项目路径-例如)幸运的是,使用新的相对文件路径变量,我们可以消除替换和捕获组周围的一些复杂性($3$5等)和RegEx本身。
first answeran other post from @Mark上修修补补,我得出了以下解决方案:

"body": [
    "namespace ${RELATIVE_FILEPATH/^([^\\\\\\/]+)[\\\\\\/]|([^\\\\\\/]+)[\\\\\\/]|(?:[^\\\\\\/]+\\.[^\\\\\\/]+)/$1${2:+.}$2/g};",
    "",
    "internal ${1|enum,interface,sealed class,sealed record,record struct|} $TM_FILENAME_BASE",
    "{",
    "    $0",
    "}"
],

(for一点测试见regex101.com不是100%准确的VSCode似乎是如何做到这一点,但哦,好吧)
。我知道这看起来还是有点糟糕,但是让我把它简化一点,分解一下
首先,为了简单起见,我们不使用\/作为分隔符,而是使用#,并删除了代码片段所需的双转义。我们的目标是:

  • RegEx:^([^#]+)#|([^#]+)#|(?:[^#]+\.[^#]+)
  • 片段替换部分:$1${2:+.}$2

此外,我们可以将RegEx分解为3个替代方案|

  1. ^([^#]+)#
  2. ([^#]+)#
  3. (?:[^#]+\.[^#]+)
    看看第一个和第二个有多相似这是因为,在本质上,两者都捕获了我们的文件夹部分,但第一个查找的是第一个文件夹
  • ^([^#]+)#查找字符串的开头(^),然后在捕获组(( ))中查找一个以上的非#符号([^#]+),后面紧跟一个# =>,这样我们就得到了捕获组$1中没有任何#的第一个文件夹
  • ([^#]+)#完全相同,但去掉了字符串开头部分=>这里找到的所有内容都落在捕获组$2中,但去掉了分隔符#
  • (?:[^#]+\.[^#]+)具有非捕获捕获组((?: ... )),它查找多个非#符号([^#]+)后面正好是一个.\.)后再接一个以上的非#符号([^#]+)=>这样我们就可以捕获文件名及其扩展名,甚至允许文件名中有额外的.,然后将其丢弃

最后,我们使用transform的格式部分(见这里)将我们的输出拼接在一起:

  • 取第一个捕获组($1),按原样写入
  • 如果第二个捕获组不为空,则写入一个点(${2:+.})(每次匹配该组时重复)
  • 添加第二个捕获组($2)(每次匹配组时重复)

有了这个,我们没有一个点(或多个)在年底,删除文件名与扩展名(无论有多少.它包含),并取代所有#(或在原来的情况下,任何\/)与.
我想我在空闲时间花了>24小时的时间来做这个(我讨厌RegEx),我能把它们花在写代码上吗?当然,但有时候追随你的完美主义和迎接挑战也会很有趣;)

相关问题