转换为camelCase


34

挑战

前几天,我在阅读Google的Java样式指南,偶然发现了他们的算法,可以将任意字符串转换为camelCase表示法。在此挑战中,您必须实现此算法,因为当您将超级竞争的Java提交编写为代码高尔夫球挑战时,您不想在头脑中做所有这些事情。

注意:我对算法做了一些小的调整。您需要使用以下指定的一种。

算法

您从任意输入字符串开始,并对它应用以下操作:

  1. 删除所有撇号 `'
  2. 通过在处拆分将结果拆分为单词
    • 不是字母数字和数字的字符 [^a-zA-Z0-9]
    • 大写字母,两侧均用小写字母包围。abcDefGhI jk例如产量abc Def Ghi jk
  3. 每个单词都小写。
  4. 除第一个单词外,每个单词的第一个字符均大写。
  5. 将所有单词重新组合在一起。

附加条款

  • 输入将仅包含可打印的ASCII。
  • 如果数字是单词中的第一个字母,请保持原样,并且不要使该单词中的其他内容成大写字母。
  • 输入将始终至少包含一个字符。

规则

测试用例

“编程难题和代码高尔夫”->“ programmingPuzzlesCodeGolf”
“ XML HTTP请求”->“ xmlHttpRequest”
“在iOS上支持IPv6吗?” ->“ supportsIpv6OnIos”
“某物,载脂蛋白的残基和标点符号”->“ somethingW1thApostrophesAndPuncTuation”
“没什么特别的”->“没什么特别的”
“ 5pecial ca5e”->“ 5pecialCa5e”
“ 1337”->“ 1337”
“ 1337-spEAk”->“ 1337Speak”
“ whatA混乱”->“ whataMess”
“ abcD”->“ abcd”
“ a”->“ a”
“ B”->“ b”

编码愉快!


3
有趣的是,我从来不知道这被称为“ camelCase”。我猜这个名字很合适……
Ashwin Gupta

4
还有更多:snake_casePascalCase
Martijn

14
@Martijn snake_case当然是因为Python。FORTH也有FORTHCASE和APL有unreadable in any case

测试用例4应该ApostropheS在输出中。
泰特斯

@Titus不,是正确的。在分割输入之前,将撇号除去。
Denker

Answers:


13

视网膜,56字节

字节数假定为ISO 8859-1编码。

T`'\`
S_`\W|_|(?<=[a-z])(?=[A-Z][a-z])
T`L`l
T`l`L`¶.
¶

在线尝试!

说明

这从字面上实现了规范:

T`'\`

除去撇号和反引号。

S_`\W|_|(?<=[a-z])(?=[A-Z][a-z])

将字符串拆分为非单词字符(在正则表达式中也排除数字和下划线),或在下划线或位置的左侧带有小写字母,在右侧带有大写字母,小写字母的位置。当一行中有两个非字母,非数字字符或更重要的字符串时,这将创建一些空段。我们摆脱了那些_选择。在此,“分割”是指将其余各部分放在自己的行上。

T`L`l

将所有内容转换为小写。

T`l`L`¶.

将换行后出现的每个字符转换为大写。由于前面没有换行符,因此可以方便地跳过第一个单词。

摆脱换行符,将所有内容重新组合在一起。


你击败了我。好东西!
mbomb007'3

这个问题可能有点怪异,但是...如果比您的回答短,而且在视网膜中,我应该发布答案吗?在您的答案出现之前,我已经在研究它了,但是后来它做了,现在我不知道是否应该发布它。
daavko

5
@daavko当然,发布它(我通常根据对现有答案的处理方式有多不同来决定...如果是完全相同的东西,但在某个地方被削掉了一个字节,我通常只是对该答案发表评论,但是如果它要短得多的话一种不同的方法,那么我只发布一个单独的答案)。
Martin Ender'3

2
@daavko虽然环顾四周是必要的。请注意,您的答案Thing虽然会保留大写字母,但不会保留大写字母。
Martin Ender'3

1
@MartinBüttner哦...我没注意到。哦,那么,我将成功回答其他挑战。
daavko

11

Java,198190字节

+3个字节,因为我忘记了\W+== [^a-zA-Z0-9_]+并且我需要匹配[^a-zA-Z0-9]+

-11字节感谢user20093 - ?:而不是if/else

因为,Java。

s->{String[]a=s.replaceAll("`|'","").split("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])");s="";for(String w:a){String t=w.toLowerCase();s+=a[0]==w?t:t.toUpperCase().charAt(0)+t.substring(1);}return s;}

这是一个lambda。像这样打电话:

UnaryOperator<String> op = s->{String[]a=s.replaceAll("`|'","").split("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])");s="";for(String w:a){String t=w.toLowerCase();s+=a[0]==w?t:t.toUpperCase().charAt(0)+t.substring(1);}return s;};
System.out.println(op.apply("Programming Puzzles & Code Golf"));

可读版本:

public static String toCamelCase(String s) {
    String[] tokens = s
            .replaceAll("`|'", "") // 1. Remove all apostrophes
            .split("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])"); // 2. Split on [\W_]+ or between [a-z] and [A-Z][a-z]
    s = ""; // Reusing s for building output is cheap
    for (String token : tokens) {
        String lowercaseToken = token.toLowerCase(); // 3. Lowercase every word
        s += tokens[0].equals(token)?lowercaseToken:lowercaseToken.toUpperCase().charAt(0) + lowercaseToken.substring(1); // 4. Uppercase first char of all but first word
        // ^ 5. Join all words back together
    }
    return s;
}

1
它不是Swift ...
CalculatorFeline'Mar

2
欢迎来到编程难题和代码高尔夫球!这是一个不错的第一答案!
Alex A.

1
@CatsAreFluffy什么?

如果将条件语句(if / else)替换为条件表达式(?:),则可以节省大约9个字节
user902383

不知道我怎么想念@ user902383-添加了-11个字节。不幸的是,我还必须添加3来匹配_令牌定界符。
CAD97

10

的JavaScript(ES6),156 154 152 148 145 141 140个字节

感谢@Neil(6个字节),@ ETHproductions(3个字节)和@ edc65(7个字节)

a=>a[r='replace'](/`|'/g,a='')[r](/[a-z](?=[A-Z][a-z])/g,'$& ')[r](/[^\W_]+/g,b=>a+=(a?b[0].toUpperCase():'')+b.slice(!!a).toLowerCase())&&a

删除撇号,然后进行替换以分割特殊字符/在大写字母之前,然后与适当的大小写合并。不幸的是,toLowerCase()toUpperCase()是烦人长,难以避免在这里...


1
我正在尝试使用另一种方法,但是您的b.slice(i>0)方法却无济于事,但是与此同时,我的匹配正则表达式/[A-Z]?([a-z0-9]|[0-9A-Z]{2,})+([A-Z](?![a-z]))?/g确实比您原本精巧的replace方法节省了2个字节。
尼尔

1
或者,我可以replace直接在您的文件上保存2个字节:replace(/[a-z](?=[A-Z][a-z])/g,'$& ')
尼尔

1
通常match...map可以替换为replace
edc65 '16

1
@ edc65通过这种方法,我至少获得了160个字节:a=>a.replace(/`|'/g,'').replace(/[a-z](?=[A-Z][a-z])/g,'$& ').replace(/[\W_]*([a-z0-9]+)[\W_]*/gi,(_,b,i)=>(i?b[0].toUpperCase():'')+b.slice(i>0).toLowerCase())
ETHproductions 2016年

2
另一方面,我想提供一个b=>a+=(a?b[0].toUpperCase():'')+b.slice(!!a).toLowerCase(),我相信可以为您节省另外4个字节。
Neil

7

vim,69 68 66

:s/[`']//g<cr>:s/[a-z]\zs\ze[A-Z][a-z]\|\W\|_/\r/g<cr>o<esc>guggj<C-v>GgU:%s/\n<cr>

vim比Perl短吗?这是什么疯狂?

:s/[`']//g<cr>           remove ` and '
:s/                      match...
 [a-z]\zs\ze[A-Z][a-z]   right before a lowercase-surrounded uppercase letter
 \|\W\|_                 or a non-word char or underscore
 /\r/g<cr>               insert newlines between parts
o<esc>                   add an extra line at the end, necessary later...
gugg                     lowercasify everything
j                        go to line 2 (this is why we added the extra line)
<C-v>G                   visual select the first char of all-but-first line
gU                       uppercase
:%s/\n<cr>               join all lines into one

感谢尼尔发现了无用的按键!


我可以看到为什么最后一个:s有一个,%但是为什么前两个有不一致?
Neil

@Neil Bah,肌肉记忆。谢谢!
门把手

5
管理是比Perl的可读性,也+1

我完全加入这个对我的.vimrc
moopet

1
@fruglemonkey 1. :%j<cr>等效且较短。2.这样在行之间增加了空格。
门把手

5

Mathematica 10.1,101个字节

""<>(ToCamelCase@{##2}~Prepend~ToLowerCase@#&@@StringCases[StringDelete[#,"`"|"'"],WordCharacter..])&

使用undocumented ToCamelCase,其作用类似于Capitalize但将其他字符设置为小写。


不在10.3.0 ..
Simmons

是对的ToCamelCase[n_,m_]:=n<>Capitalize/@m吗 看起来是这么回事。以及为什么Prepend#~ToCamelCase~{##2}工作时使用?
CalculatorFeline

@CatsAreFluffy这给了我ToCamelCase::argx: ToCamelCase called with 2 arguments; 1 argument is expected.
LegionMammal978 '16

好吧,CamelCase如何工作?只是ToCamelCase[n_]:=""<>Capitalize/@n
CalculatorFeline

@CatsAreFluffy,请参阅
LegionMammal978

5

朱莉娅98 89字节

s->lcfirst(join(map(ucfirst,split(replace(s,r"['`]",""),r"[a-z]\K(?=[A-Z][a-z])|\W|_"))))

这是一个匿名函数,它接受一个字符串并返回一个字符串。要调用它,请将其分配给变量。

这里的方法与Doorknob的Perl答案相同:将replace带有空字符串的撇号和反引号split放入匹配必要情况的正则表达式数组中,mapucfirst函数将每个元素的第一个字母大写,join然后返回数组转换为字符串,然后lcfirst将第一个字符转换为小写的结果。


我一直喜欢Julia作为功能更强大,更有趣的Python,但我讨厌end语法。也许我将对所有内容使用匿名函数,然后再也不必输入end:D

4

Perl 67 +1 = 68字节

y/'`//d;s/([a-z](?=[A-Z][a-z]))|\W|_/$1 /g;$_=lc;s/^ +| +(.)/\u$1/g

需要-p标志,-l对于多行:

$ perl -pl camelCase.pl input.txt
programmingPuzzlesCodeGolf
xmlHttpRequest
supportsIpv6OnIos:
someThingW1thApostrophesAndPuncTuation
nothingSpecial
5pecialCa5e
1337
1337Speak
abcd

怎么运行的:

y/'`//d;                            # Remove ' and `
s/([a-z](?=[A-Z][a-z]))|\W|_/$1 /g; # Replace according to '2. Split...' this will create
                                    #   a space separated string.
$_=lc;                              # lower case string
s/^ +| +(.)/\u$1/g                  # CamelCase the space separated string and remove any
                                    #   potential leading spaces.

2

Perl, 87 80 78字节

y/'`//d;$_=join'',map{ucfirst lc}split/[a-z]\K(?=[A-Z][a-z])|\W|_/,$_;lcfirst

-p标志添加的字节。

首先,我们使用 y///音译运算符d删除'`输入中的所有字符:

y/'`//d;

然后是代码的内容:

                         split/[a-z]\K(?=[A-Z][a-z])|\W|_/,$_;

$_使用花式将输入字符串拆分到适当的位置\K匹配字符串中以将其前面的部分排除在实际匹配之外)

          map{ucfirst lc}

(映射字符串的每个拆分部分,并将整个字符串小写,然后将修改后的字符串的第一个字符大写)

$_=join'',

(加入空字符串并重新分配到魔术下划线$_,该下划线将在最后打印出来)

最后,我们通过对正则表达式进行匹配来\l小写第一个字母,并使用带有内置函数的替换字符串,比以前的方法节省2个字节:

lcfirst

感谢@MartinBüttner提供7个字节([^a-zA-Z\d]-> \W|_)!


1
我真羡慕\K...;)
马丁·恩德

2

Lua,127字节

t=''l=t.lower z=io.read()for x in z:gmatch('%w+')do t=t..(t==''and l(x:sub(1,1))or x:sub(1,1):upper())..l(x:sub(2))end return t

接受来自stdin的字符串并返回驼峰化的结果。

可能仍会寻找更好的解决方案,因为将所有内容存储在变量中感觉效率低下。

但是总的来说,很简单:

 z:gmatch('%w+')

这就是为我节省了一些字节的美。gmatch将根据模式分割字符串:%w+仅字母数字。

之后就是简单的字符串操作。string.upper,string.lower完成。


2

PHP,145个 122 133字节的

<?=join(split(" ",lcfirst(ucwords(strtolower(preg_replace(["#`|'#","#\W|_#","#([a-z])([A-Z][a-z])#"],[""," ","$1 $2"],$argv[1]))))));

保存到文件,然后从CLI调用。
从单个命令行参数获取输入;必要时转义引号和空格。

分解

<?=                 // 9. print result
join(split(" ",     // 8. remove spaces
    lcfirst(        // 7. lowercase first character
    ucwords(        // 6. uppercase first character in every word
    strtolower(     // 5. lowercase everything
    preg_replace(
        ["#`|'#",   "#\W|_#",   "#([a-z])([A-Z][a-z])#"],
        ["",        " ",        "$1 $2"],
        // 2. replace apostrophes with empty string (remove them)
                    // 3. replace non-word characters with space
                                // 4. insert space before solitude uppercase
        $argv[1]    // 1. take input from command line
    ))))
));

lcfirst允许将其减少为一个命令,节省23个字节。
对于其他替换情况,固定撇号的成本为11个字节。


1

科特林,160字节

fun a(s: String)=s.replace(Regex("['`]"),"").split(Regex("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])")).map{it.toLowerCase().capitalize()}.joinToString("").decapitalize()

我的目标是成为Scala,另一个“替代Java”,因此我对自己的结果感到满意。我从Java答案中窃取了正则表达式。

用以下方法进行测试:

fun main(args: Array<String>) {
    val testCases = arrayOf(
            "Programming Puzzles & Code Golf",
            "XML HTTP request",
            "supports IPv6 on iOS?",
            "SomeThing w1th, apo'strophe's and' punc]tuation",
            "nothing special",
            "5pecial ca5e",
            "1337",
            "1337-spEAk",
            "abcD",
            "a",
            "B")
    testCases.forEach { println(a(it)) }

}

在这一点上,我认为每个人都在“借用”经过优化的正则表达式\W|_|(?<=[a-z])(?=[A-Z][a-z])或对其稍加修改。[\W_]+
CAD97

您可以在地图和扩展功能上保存一些fun String.a()=replace(Regex("['`]"),"").split(Regex("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])")).joinToString(""){it.toLowerCase().capitalize()}.decapitalize()
poss

1

Scala中,181 170 144

def f(s:String)={val l=s.replaceAll("'|`","")split("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])")map(_.toLowerCase);l(0)+l.tail.map(_.capitalize).mkString}

测试人员:

val testCases = List(
  "Programming Puzzles & Code Golf" -> "programmingPuzzlesCodeGolf",
  "XML HTTP request" -> "xmlHttpRequest"
  // etc
)
println(testCases.map(t=>if(t._2!=f(t._1))s"FAIL:${f(t._1)}"else"PASS").mkString("\n"))

CAD97的支持和对Nathan Merrill的歉意:)


1
替换[^a-zA-Z0-9]+为可以节省6个字节[\\W_]+
CAD97

0

C 272个字符

C程序将引号中的字符串传递给camelCase作为参数1。在此问题陈述中有很多陷阱...

#define S strlen(t)
#define A isalnum(t[i])
j=0;main(i,v)char**v;{char*p=v[1],*t;char o[99]={0};while(t=strtok(p," [{(~!@#$%^*-+=)}]")){i=0;p+=S+1;while((!A)&&i<S)i++;if(i!=S){o[j]=((j++==0)?tolower(t[i++]):toupper(t[i++]));while(i<S){if(A)o[j++]=t[i];i++;}}}puts(o);}

你需要#include<string.h>strlenstrtoktoupper,和#include<ctype.h>isalnum
Mego

我在cygwin中使用gcc 3.4.4不需要它。假定为extern int,则必须自动链接​​它们。
cleblanc 2016年

随着./camel "Programming Puzzles & Code Golf"在Cygwin上(用gcc 3.4.4编译),我得到programmingPuzzlesCodeEGolf。与5.3.0相同的输出。
Mego

废话 我也是。打高尔夫球的时候我一定创造了一个错误。我现在正在看...
cleblanc '16

问题是我在打完高尔夫球后又添加了其他记号生成器字符串,并且测试不够好。如果从strtok调用中删除“&”,则该输入将起作用。
cleblanc '16

0

JavaScript,123个字节

v=>v[r="replace"](/[`']/g,"")[r](/^.|.$|[A-Z][^a-z]+/g,x=>x.toLowerCase())[r](/[^a-z0-9]+./ig,x=>x.slice(-1).toUpperCase())

可读版本

v=>
  v.replace(/[`']/g,"")
  .replace(/^.|.$|[A-Z][^a-z]+/g,x=>x.toLowerCase())
  .replace(/[^a-z0-9]+./ig,x=>x.slice(-1).toUpperCase())

删除撇号,使第一个字符小写,最后一个字符小写,以及多个大写字符的任何分组,匹配1个或多个非字母数字字符+ 1个其他字符的任何组,并用最后一个大写字母替换。

Mrw247解决方案中的[r =“ replace”]技巧。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.