单个正则表达式将驼峰命名法转换为破折号分隔的小写形式。

6

我正在尝试编写一个SublimeText的代码片段,用于JavaScript的import语句。我希望格式如下:

import MyFooBar from 'my-foo-bar';

我的正则表达式输入是MyFooBar,输出需要是my-foo-bar。我在Regex - CamelCase to lower case with underscores中找到了一个几乎可行的答案:

搜索

((?<=.)[A-Z][a-zA-Z]*)|((?<=[a-zA-Z])\d+)

替换为

-\L$1$2

答案说只需使用JavaScript的.toLowerCase()方法进行小写处理,但SublimeText片段使用perl,而我对perl知之甚少。快速搜索发现,我可以在替换的开头使用\L来进行小写处理。
/((?<=.)[A-Z][a-zA-Z0-9]*)|((?<=[a-zA-Z])\d+)/\L-\1\2/g

这段代码对除第一个字符段外的所有字符段都有效,所以MyFooBar将变成My-foo-bar

我想也许我可以按顺序运行两个正则表达式,但是perl或Sublime似乎无法识别它们。

有什么想法吗?

编辑:

当我说它使用perl时,我只是指它使用了perl正则表达式。就我所知,我不能实际执行任意代码;我只能指定一个perl可以执行的正则表达式。

这是我的片段的完整文本:

<snippet>
    <content><![CDATA[
import ${1:module} from '${2:./path/}${1/((?<=.)[A-Z][a-zA-Z0-9]*)|((?<=[a-zA-Z])\d+)/\L-\1\2/g}';
]]></content>
    <!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
    <tabTrigger>import</tabTrigger>
    <!-- Optional: Set a scope to limit where the snippet will trigger -->
    <scope>source.js</scope>
</snippet>

1
为什么一定要用正则表达式呢?这个问题可以通过一个适当的搜索和替换函数更容易地处理,而 Perl 就有这样的函数... - cat
@cat 我正在学习如何创建代码片段,但是http://sublimetext.info/docs/en/extensibility/snippets.html#substitutions 只展示了一种替换方式。 - dx_over_dt
1
@anubhava 的最后一句话是问题所在。你运行了两个正则表达式来纠正第一个字符上的“错误”,但显然没有起作用。 - Christoph
请上传您当前的完整代码片段。 - revo
你需要一个条件替换模式(PCRE 不支持此功能),或者查看如何在同一行上使用两个正则表达式。顺便问一下,你确定是 PCRE 吗?不是 Boost 吗? - Wiktor Stribiżew
显示剩余3条评论
3个回答

1
我已将正则表达式更改为更实用且可能更简单的内容。
** 更新
<snippet>
    <content><![CDATA[
import ${1:module} from '${2:./path/}${1/(^[A-Z][a-z]+|[a-z])([A-Z])/\L\1-\2/g}';
]]></content>
    <!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
    <tabTrigger>import</tabTrigger>
    <scope>source.js</scope>
</snippet>

这将在我的模块文件名前添加一个“-”。我可以删除它,但现在基本上就是我必须用替换第一个大写字符来完成的。 - dx_over_dt
@dfoverdx 噢,是的,但当我按下Enter键时,那个额外的破折号就不见了! - revo
@dfoverdx 修改了正则表达式,请再次检查。 - revo
1
如此接近了。我以为它可以工作,直到我尝试了“环境”。如果没有第二个大写字母,那么这个单词就不会被替换。只替换第一个字符并不是什么大问题。唉,我认为这个特定的努力是不可能的。 - dx_over_dt
2
通过将-\2更改为(?2-\2)可使其成为条件语句。 完整的正则表达式行: import ${1:module} from '${2:./path/}${1/(^[A-Z][a-z]*|[a-z])([A-Z])?/\L\1(?2-\2)/g}'; - r-stein
显示剩余2条评论

0

丑陋(substr())但有效:

$x = "MyFooBar";
$x =~ s/(?:^|(?<=[a-z])(?=[A-Z]))(.)/-lc($1)/eg;
$x = substr($x, 1);
print $x;
// my-foo-bar

ideone.com上查看演示。


点赞,但如果您传入类似于MyFooBarID这样的内容怎么办? - lintmouse

0

这个花了我一点时间,但我相信它可以在一个正则表达式内完成你想要的所有操作:

use warnings;
use strict;

while (<DATA>){
    chomp;
    s/([[:upper:]].*?)(?=(?:[[:upper:]]|$))/$+[0]!=length($_) ? lc($1).'-' : lc($1)/ge;
    print "$_\n";
}

__DATA__
MyCamelCase
AVeryLongCamelCaseStringWMXThat

输出:

my-camel-case
a-very-long-camel-case-string-w-m-x-that

解释:它查找大写字母,并将该字母与所有其他字母一起捕获,直到它在零宽度前瞻中看到另一个大写字母或字符串结束。在替换侧,我们使用 /e 修饰符,这意味着右侧是一个表达式(可执行代码)。如果最近匹配的结尾 ($+[0]) 小于字符串长度,则我们进行小写转换 (lc()) 并附加一个 -。如果字符串长度与上次匹配的结尾相同,则我们将其转换为小写并完成。


这不会起作用,因为Sublime片段实际上并没有解释Perl——它们只是使用PCRE语法。 - Matt Jacob
我将其复制并粘贴到我的片段中并运行了它。import MyFooBar from './path/My[1]!=length$_-1 ? lcMy.'-' : lcMyFoo[1]!=length$_-1 ? lcFoo.'-' : lcFooBar[1]!=length$_-1 ? lcBar.'-' : lcBar'; 尽管如此,这是一个不错的尝试! - dx_over_dt
啊,糟糕 :) 我错过了代码不执行的部分。 - stevieb
2
这是我第一次使用$+[0]$-[0],所以至少我们中的一个人从中受益了 :) - stevieb

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