Конвертировать в camelCase


34

Соревнование

На днях я читал Руководство по стилю Java от Google и наткнулся на их алгоритм преобразования любой произвольной строки в нотацию camelCase. В этой задаче вы должны реализовать этот алгоритм, так как вы не хотите делать все это в своей голове, когда вы пишете свои суперконкурентные представления Java для задач кода-гольфа.

Примечание: я внес небольшие изменения в алгоритм. Вам нужно использовать тот, который указан ниже.

Алгоритм

Вы начинаете с произвольной входной строки и применяете к ней следующие операции:

  1. Удалить все апострофы `'
  2. Разделите результат на слова, разделив на
    • символы, которые не являются буквенно-цифровыми и не являются цифрами [^a-zA-Z0-9]
    • Прописные буквы, которые с обеих сторон окружены строчными буквами. abcDefGhI jkнапример урожайностьabc Def Ghi jk
  3. Строчные каждое слово
  4. Прописные буквы первого символа каждого, кроме первого слова.
  5. Объедините все слова вместе.

Дополнительные замечания

  • Ввод будет содержать только печатный ASCII.
  • Если цифра является первой буквой в слове, оставьте ее как есть и не вводите в это слово что-то еще.
  • На входе всегда будет хотя бы один символ.

правила

Контрольные примеры

"Программирование Пазлов и Код Гольф" -> "ПрограммированиеPuzzlesCodeGolf"
«HTTP HTTP запрос» -> «xmlHttpRequest»
"поддерживает IPv6 на iOS?" -> "SupportIpv6OnIos"
«SomeThing w1th, apo'strophe's и 'punc] tuation» -> «someThingW1thApostrophesAndPuncTuation»
"ничего особенного" -> "ничего особенного"
"5pecial ca5e" -> "5pecialCa5e"
"1337" -> "1337"
"1337-spEAk" -> "1337Speak"
"WhatA беспорядок" -> "whataMess"
"abcD" -> "abcd"
"а" -> "а"
"B" -> "B"

Удачного кодирования!


3
Интересно, я никогда не знал, что это называлось "CamelCase". Полагаю, имя подходит ...
Эшвин Гупта

4
Есть еще: snake_case&PascalCase
Martijn

14
@ Martijn snake_caseиз-за Python, конечно. FORTH также имеет FORTHCASEи APL имеетunreadable in any case
кошка

Контрольный пример 4 должен иметь ApostropheSна выходе.
Тит

@ Титус Нет, это правильно. Апострофы удаляются до разделения входных данных.
Денкер

Ответы:


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

Этот вопрос может быть немного странным, но ... я должен опубликовать свой ответ, если он короче, чем ваш, а также в Retina? Я работал над этим до того, как ваш ответ появился, но потом он появился, и теперь я не знаю, стоит ли его публиковать.
Даавко

5
@daavko Конечно, опубликуйте его (я обычно решаю, исходя из того, насколько подход отличается от существующего ответа ... если это точно то же самое, когда где-то сброшен байт, я обычно просто комментирую этот ответ, но если он намного короче другого подхода, тогда я бы просто опубликовал отдельный ответ).
Мартин Эндер

2
@daavko Взгляд необходим, хотя. Обратите внимание, что ваш ответ не сохраняет заглавные буквы, Thingхотя должен.
Мартин Эндер

1
@ MartinBüttner Ох ... я этого не заметил. Ну что ж, тогда я успешно отвечу на другой вызов.
Даавко

11

Ява, 198 190 байт

+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;}

Это лямбда. Звоните так:

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
Это не Свифт ...
CalculatorFeline

2
Добро пожаловать в Программирование Пазлов и Code Golf! Это хороший первый ответ!
Алекс А.

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, похоже, мое регулярное выражение экономит 2 байта по сравнению с вашим остроумным replaceподходом.
Нил

1
Или я мог бы просто сэкономить 2 байта на вашем replace:replace(/[a-z](?=[A-Z][a-z])/g,'$& ')
Нил

1
Обычно match...mapможно заменить наreplace
edc65

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

2
С другой стороны, я хотел бы предложить, b=>a+=(a?b[0].toUpperCase():'')+b.slice(!!a).toLowerCase()что, я считаю, экономит вам еще 4 байта.
Нил

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есть, %но почему несоответствие в первых двух?
Нил

@ Нил Бах, мышечная память. Благодарность!
Дверная ручка

5
Может быть менее читабельным, чем Perl, тоже +1
кот

Я полностью добавляю это к своему .vimrc
moopet

1
@fruglemonkey 1. :%j<cr>эквивалентен и короче. 2. Это добавляет пробелы между строками.
Дверная ручка

5

Mathematica 10,1, 101 байт

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

Использует недокументированное ToCamelCase, которое работает аналогично, Capitalizeно устанавливает другие символы в нижний регистр.


Не в 10.3.0 ..
Симмонс

Является ли ToCamelCase[n_,m_]:=n<>Capitalize/@mправильно? Похоже на это. А зачем использовать Prependкогда #~ToCamelCase~{##2}работает?
CalculatorFeline

@CatsAreFluffy Это дает мнеToCamelCase::argx: ToCamelCase called with 2 arguments; 1 argument is expected.
LegionMammal978

Ну, как работает 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|_"))))

Это анонимная функция, которая принимает строку и возвращает строку. Чтобы вызвать его, присвойте его переменной.

Подход здесь такой же , как в дверную ручку в Perl ответа : replaceапостроф и обратные кавычки с пустой строкой, splitв массив на регулярное выражение , которое соответствует необходимых случаях, функция над массивом прописной первую букву каждого элемента массива обратно в строку, и результат для преобразования первого символа в нижний регистр.mapucfirstjoinlcfirst


Мне всегда нравилась Джулия как более функциональный, более интересный Python, но я ненавижу endсинтаксис. Может быть, я просто буду использовать анонимные функции для всего, тогда мне никогда не придется печатать end: D
cat

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

Луа, 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

Принимает строку из стандартного ввода и возвращает верблюжьи результаты.

Вероятно, все еще будем искать лучшее решение, поскольку хранение всего в переменной кажется неэффективным.

Но как бы то ни было, в целом все довольно просто:

 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()
возможно,

1

Скала, 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}

Tester:

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 и извинения Натану Мерриллу :)


1
Вы можете сохранить 6 байтов, заменив [^a-zA-Z0-9]+на [\\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>для strlen, strtokи toupper, и #include<ctype.h>для isalnum.
Mego

Мне не нужно было использовать gcc 3.4.4 в Cygwin. Они должны быть автоматически связаны, предполагая extern int.
cleblanc

С ./camel "Programming Puzzles & Code Golf"на Cygwin (скомпилировано с GCC 3.4.4), я получаю programmingPuzzlesCodeEGolf. Тот же вывод с 5.3.0.
Mego

Дерьмо. я тоже. Я, должно быть, создал ошибку во время игры в гольф. Я смотрю на это сейчас ...
cleblanc

Проблема заключалась в том, что я добавил другие строки токенизатора после игры в гольф и не достаточно хорошо их протестировал. Если вы удалите '&' из вызова strtok, он будет работать на этом входе.
cleblanc

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 другой символ, замените его последним символом с заглавной буквы.

[r = "replace"] трюк из решения Mrw247.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.