Convertir en camelCase

34

Le défi

Je lisais le Java Style Guide de Google l'autre jour et je suis tombé sur son algorithme pour convertir toute chaîne arbitraire en notation camelCase. Dans ce défi, vous devez implémenter cet algorithme, car vous ne voulez pas faire tout cela dans votre tête lorsque vous écrivez vos soumissions Java extrêmement compétitives aux défis de code-golf.

Note: J'ai fait quelques petits ajustements à l'algorithme. Vous devez utiliser celui spécifié ci-dessous.

L'algorithme

Vous commencez avec une chaîne d'entrée arbitraire et appliquez-lui les opérations suivantes:

  1. Supprimer toutes les apostrophes `'
  2. Diviser le résultat en mots en divisant en
    • caractères non alphanumériques et non numériques [^a-zA-Z0-9]
    • Lettres majuscules entourées de lettres minuscules des deux côtés. abcDefGhI jkpar exemple les rendementsabc Def Ghi jk
  3. Minuscule chaque mot.
  4. Majuscule le premier caractère de chaque mot sauf le premier.
  5. Rejoins tous les mots ensemble.

Notes complémentaires

  • L'entrée ne contiendra que l'ASCII imprimable.
  • Si un chiffre est la première lettre d'un mot, laissez-le tel quel et ne capitalisez pas autre chose dans ce mot.
  • L'entrée aura toujours au moins un caractère.

Règles

Cas de test

"Programmation Puzzles & Code Golf" -> "programmationPuzzlesCodeGolf"
"Demande HTTP XML" -> "xmlHttpRequest"
"supporte IPv6 sur iOS?" -> "supportsIpv6OnIos"
"Quelque chose avec apo'strophe's et 'punc] tuation" -> "someThingW1thApostrophesAndPuncTuation"
"rien de spécial" -> "rien de spécial"
"5pecial ca5e" -> "5pecialCa5e"
"1337" -> "1337"
"1337-spEAk" -> "1337Speak"
"quel désordre" -> "whataMess"
"abcD" -> "abcd"
"a" -> "a"
"B" -> "b"

Bon codage!

Denker
la source
3
Intéressant, je n'ai jamais su que cela s'appelait "camelCase". Je suppose que le nom lui convient ...
Ashwin Gupta
4
Il y a plus: snake_case&PascalCase
Martijn
14
@Martijn à snake_casecause de Python, bien sûr. FORTH a également FORTHCASEet APL aunreadable in any case
Cat
Le cas de test 4 devrait avoir ApostropheSdans la sortie.
Titus
@ Titus Non, c'est correct. Les apostrophes sont supprimés avant que l'entrée ne soit scindée.
Denker

Réponses:

13

Retina , 56 octets

Le nombre d'octets suppose un codage ISO 8859-1.

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

Essayez-le en ligne!

Explication

Cela implémente littéralement la spécification:

T`'\`

Supprimer les apostrophes et les backticks.

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

Divisez la chaîne en caractères non-mots (dans regex, cela exclut également les chiffres et les tirets bas), ou les traits de soulignement ou les positions qui ont une lettre minuscule à gauche et une majuscule, la minuscule à droite. Cela créerait des segments vides quand il y a deux caractères non-lettres, non-numériques dans une ligne, ou plus important au début de la chaîne. Nous nous débarrassons de ceux qui ont l' _option. Dans ce cas, "fractionner" signifie mettre chaque partie restante sur sa propre ligne.

T`L`l

Convertissez tout en minuscule.

T`l`L`¶.

Convertissez chaque caractère qui apparaît après le saut de ligne en majuscule. Cela évite le premier mot car il n'y a pas de saut de ligne devant lui.

Débarrassez-vous des sauts de ligne pour réunir le tout.

Martin Ender
la source
Tu m'as battu à ça. Joli!
mbomb007
Cette question est peut-être un peu bizarre, mais ... devrais-je poster ma réponse si elle est plus courte que la votre et également dans Retina? J'y travaillais avant la publication de votre réponse, mais c'est arrivé et maintenant je ne sais pas si je devrais la poster.
Daavko
5
@daavko Bien sûr, postez-le (je décide généralement en fonction de la différence d'approche par rapport à la réponse existante ... si c'est exactement la même chose avec un octet supprimé quelque part, je commente normalement cette réponse, mais si elle est beaucoup plus courte d'une approche différente, alors je posterais juste une réponse séparée).
Martin Ender
2
@daavko Le lookaround est cependant nécessaire. Notez que votre réponse ne conserve pas la capitalisation de Thingbien qu’elle le devrait.
Martin Ender
1
@ MartinBüttner Oh ... Je n'ai pas remarqué cela. Oh bien, je vais réussir à relever un autre défi, alors.
Daavko
11

Java, 198 190 octets

+3 octets parce que j'ai oublié que \W+== [^a-zA-Z0-9_]+et que je dois correspondre[^a-zA-Z0-9]+

-11 octets grâce à user20093 - ?:au lieu de if/else

Parce que, 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;}

C'est un lambda. Appelle comme ça:

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"));

Version lisible:

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;
}
CAD97
la source
1
Ce n'est pas rapide ...
CalculatorFeline
2
Bienvenue dans Programming Puzzles & Code Golf! C'est une belle première réponse!
Alex A.
1
@CatsAreFluffy Quoi?
Cat
Si vous remplacez l'instruction conditionnelle (if / else) par une expression conditionnelle (? :), vous pouvez économiser environ 9 octets
user902383
Je ne sais pas comment j'ai raté cela @ user902383 - ajouté pour -11 octets. Malheureusement, j’ai dû ajouter 3 aussi bien _comme un délimiteur de jeton.
CAD97
10

JavaScript (ES6), 156 154 152 148 145 141 141 140 octets

Merci @Neil (6 octets), @ETHproductions (3 octets) et @ edc65 (7 octets)

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

Supprime les apostrophes, puis effectue un remplacement pour séparer les caractères spéciaux / avant les majuscules entourées, puis se combine avec une casse appropriée. Malheureusement, toLowerCase()et toUpperCase()sont ennuyeusement long et difficile à éviter ici ...

Mwr247
la source
1
Je travaillais sur une approche différente que votre b.slice(i>0)approche met hors de l'eau, mais entre-temps, mon regex de match /[A-Z]?([a-z0-9]|[0-9A-Z]{2,})+([A-Z](?![a-z]))?/gsemble économiser 2 octets de plus que votre replaceapproche ingénieuse .
Neil
1
Ou je pourrais juste économiser 2 octets sur votre replacedirectement:replace(/[a-z](?=[A-Z][a-z])/g,'$& ')
Neil
1
match...mapPeut généralement être remplacé parreplace
edc65
1
@ edc65 J'obtiens un minimum de 160 octets avec cette approche: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
D'autre part, je voudrais offrir b=>a+=(a?b[0].toUpperCase():'')+b.slice(!!a).toLowerCase()ce qui, je crois, vous épargne 4 octets supplémentaires.
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 plus court que Perl?! Quelle est cette folie?

: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

Merci à Neil d' avoir remarqué une frappe inutile!

Poignée de porte
la source
Je peux voir pourquoi le dernier :sa un %mais pourquoi l'incohérence dans les deux premiers?
Neil
@ Neil Bah, mémoire musculaire. Merci!
Poignée de porte
5
Gère être moins lisible que Perl, aussi +1
cat
J'ajoute totalement cela à mon .vimrc
moopet
1
@fruglemonkey 1. :%j<cr>est équivalent et plus court. 2. Cela ajoute des espaces entre les lignes.
Poignée de porte
5

Mathematica 10.1, 101 octets

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

Utilise le non documenté ToCamelCase, qui fonctionne de la même façon Capitalizemais définit les autres caractères en minuscule.

LegionMammal978
la source
Pas dans 10.3.0 ..
A Simmons
Est ToCamelCase[n_,m_]:=n<>Capitalize/@mcorrect? On dirait bien. Et pourquoi utiliser Prependquand #~ToCamelCase~{##2}fonctionne?
CalculatorFeline
@CatsAreFluffy Cela me donneToCamelCase::argx: ToCamelCase called with 2 arguments; 1 argument is expected.
LegionMammal978
Comment fonctionne CamelCase? Juste ToCamelCase[n_]:=""<>Capitalize/@n?
CalculatorFeline
@CatsAreFluffy, voir ceci .
LegionMammal978
5

Julia, 98 89 octets

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

Il s'agit d'une fonction anonyme qui accepte une chaîne et retourne une chaîne. Pour l'appeler, assignez-le à une variable.

L’approche est la même que dans la réponse Perl de Doorknob : replaceapostrophes et backticks avec la chaîne vide, splitdans un tableau sur une expression régulière qui correspond aux cas nécessaires, mapla ucfirstfonction sur le tableau pour mettre en majuscule la première lettre de chaque élément, joinle tableau dans une chaîne, et lcfirstle résultat pour convertir le premier caractère en minuscule.

Alex A.
la source
J'ai toujours aimé Julia en tant que Python plus fonctionnel et plus intéressant, mais je déteste la endsyntaxe. J'utiliserai peut-être des fonctions anonymes pour tout, mais je n'aurai jamais à taper end: D
cat
4

Perl 67 + 1 = 68 octets

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

Nécessite le -pdrapeau, et -lpour plusieurs lignes:

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

Comment ça marche:

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.
andlrc
la source
2

Perl, 87 80 78 octets

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

Octet ajouté pour le -pdrapeau.

Tout d'abord, nous utilisons l' y///opérateur de translittération pour dsupprimer tous les '`caractères de l'entrée:

y/'`//d;

Puis vient la viande du code:

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

(divisez la chaîne d'entrée $_aux emplacements appropriés, en utilisant la fantaisie \Kde la chaîne de correspondance pour exclure la partie la précédant de la correspondance réelle)

          map{ucfirst lc}

(mappez chaque partie de la chaîne et mettez la chaîne entière en minuscule, puis mettez le premier caractère de la chaîne modifiée en majuscule)

$_=join'',

(rejoindre sur une chaîne vide et réaffecter à un soulignement magique $_, qui est imprimé à la fin)

Enfin, nous mettons la première lettre en\l minuscule en la faisant correspondre par expression rationnelle et en utilisant dans la chaîne de remplacement avec une valeur intégrée, en économisant 2 octets par rapport à la méthode précédente:

lcfirst

Merci à @ MartinBüttner pour 7 octets ( [^a-zA-Z\d]-> \W|_)!

Poignée de porte
la source
1
Comment j'envie ça \K...;)
Martin Ender
2

Lua, 127 octets

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

Accepte une chaîne de stdin et renvoie des résultats camélisés.

Je vais probablement chercher une meilleure solution car tout stocker dans une variable semble inefficace.

Mais de toute façon, assez simple en général:

 z:gmatch('%w+')

C'est la beauté qui m'a sauvé un peu d'octets. gmatch divisera la chaîne en fonction du modèle: %w+qui ne saisit que les caractères alphanumériques.

Après cela, c’est de simples opérations sur les chaînes. string.upper, string.lower et done.

Skyl3r
la source
2

PHP, 145 122 133 octets

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

Enregistrer dans un fichier, appelez à partir de la CLI.
Prend les entrées à partir d'un seul argument de ligne de commande; citations d'échappement et espaces blancs si nécessaire.

panne

<?=                 // 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
    ))))
));

lcfirstautorisé à réduire cela à une seule commande, économisant 23 octets.
La fixation des apostrophes coûte 11 octets pour le cas de remplacement supplémentaire.

Titus
la source
1

Kotlin , 160 octets

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

Mon but était d'être Scala, l'autre "alternative Java", donc je suis assez content de mes résultats. J'ai volé la regex de la réponse Java .

Testez-le avec:

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)) }

}
Nathan Merrill
la source
À ce stade, je pense que tout le monde "emprunte" la regex optimisée \W|_|(?<=[a-z])(?=[A-Z][a-z])ou la modifie légèrement, par exemple. [\W_]+
CAD97
vous pouvez en sauvegarder sur la carte et la fonction d’extensionfun 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}

Testeur:

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"))

Accessoires à CAD97 et excuses à Nathan Merrill :)

heureux
la source
1
Vous pouvez économiser 6 octets en remplaçant [^a-zA-Z0-9]+par [\\W_]+.
CAD97
0

C 272 caractères

La chaîne de transmission du programme C à camelCase est placée entre guillemets en tant qu'argument 1. Il y a beaucoup de pièges dans cette déclaration de problème ...

#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);}
cleblanc
la source
Vous devez #include<string.h>pour strlen, strtoket toupper, et #include<ctype.h>pour isalnum.
Mego
Je n'en avais pas besoin en utilisant gcc 3.4.4 dans cygwin. Ils doivent être automatiquement liés, en supposant que extern int.
cleblanc
Avec ./camel "Programming Puzzles & Code Golf"sur cygwin (compilé avec gcc 3.4.4), je reçois programmingPuzzlesCodeEGolf. Même résultat avec 5.3.0.
Mego
Merde. moi aussi. J'ai dû créer un virus en le jouant au golf. Je le regarde maintenant ...
cleblanc
Le problème était que j'ai ajouté les autres chaînes de tokenizer après le golf et que je ne l'ai pas testé assez bien. Si vous supprimez le '&' de l'appel strtok, cela fonctionne sur cette entrée.
cleblanc
0

JavaScript, 123 octets

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

Version lisible

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

Supprimez les apostrophes, placez le premier caractère en minuscule, le dernier caractère en minuscule et tout regroupement de plusieurs caractères majuscules en faisant correspondre tout groupe d'un ou plusieurs caractères non alphanumériques + 1 autre caractère en remplaçant par le dernier caractère en majuscule.

[r = "remplace"] astuce de la solution de Mrw247.

Grax32
la source