In camelCase konvertieren

34

Die Herausforderung

Ich habe neulich den Java Style Guide von Google gelesen und bin über deren Algorithmus gestolpert, um beliebige Zeichenfolgen in die CamelCase-Notation umzuwandeln. In dieser Herausforderung müssen Sie diesen Algorithmus implementieren, da Sie nicht alles im Kopf haben möchten, wenn Sie Ihre wettbewerbsfähigen Java-Einreichungen für Code-Golf-Herausforderungen schreiben.

Hinweis: Ich habe einige kleine Anpassungen am Algorithmus vorgenommen. Sie müssen das unten angegebene verwenden.

Der Algorithmus

Sie beginnen mit einer beliebigen Eingabezeichenfolge und wenden die folgenden Operationen darauf an:

  1. Entfernen Sie alle Apostrophe `'
  2. Teilen Sie das Ergebnis in Wörter auf, indem Sie bei aufteilen
    • Zeichen, die nicht alphanumerisch und keine Ziffer sind [^a-zA-Z0-9]
    • Großbuchstaben, die auf beiden Seiten von Kleinbuchstaben umgeben sind. abcDefGhI jkzum Beispiel Ausbeutenabc Def Ghi jk
  3. Jedes Wort in Kleinbuchstaben.
  4. Großschreibung des ersten Zeichens jedes bis auf das erste Wort.
  5. Verbinde alle Wörter wieder miteinander.

Zusätzliche Bemerkungen

  • Die Eingabe enthält nur druckbare ASCII-Daten.
  • Wenn eine Ziffer der erste Buchstabe in einem Wort ist, lassen Sie es so, wie es ist, und markieren Sie nichts anderes in diesem Wort.
  • Die Eingabe hat immer mindestens ein Zeichen.

Regeln

  • Funktion oder Vollprogramm erlaubt.
  • Standardregeln für die Eingabe / Ausgabe.
  • Es gelten Standardlücken .
  • Dies ist , also gewinnt die niedrigste Byte-Anzahl. Tiebreaker ist eine frühere Vorlage.

Testfälle

"Programmierpuzzles & Code Golf" -> "ProgrammierpuzzlesCodeGolf"
"XML-HTTP-Anforderung" -> "xmlHttpRequest"
"Unterstützt IPv6 unter iOS?" -> "supportedIpv6OnIos"
"SomeThing w1th, apo'strophe's and 'punc] tuation" -> "someThingW1thApostrophesAndPuncTuation"
"nichts besonderes" -> "nichts besonderes"
"5pecial ca5e" -> "5pecial ca5e"
1337 -> 1337
"1337-spEAk" -> "1337Speak"
"whatA mess" -> "whataMess"
"abcD" -> "abcd"
"a" -> "a"
B -> b

Viel Spaß beim Codieren!

Denker
quelle
3
Interessant, ich wusste nie, dass dies "camelCase" heißt. Name ist passend, nehme ich an ...
Ashwin Gupta
4
Es gibt mehr: snake_case&PascalCase
Martijn
14
@ Martijn natürlich snake_casewegen Python. FORTH hat auch FORTHCASEund APL hatunreadable in any case
Katze
Testfall 4 sollte ApostropheSin der Ausgabe haben.
Titus
@Titus Nein, das ist richtig. Apostrophe werden entfernt, bevor die Eingabe aufgeteilt wird.
Denker

Antworten:

13

Netzhaut , 56 Bytes

Die Anzahl der Bytes setzt die Kodierung nach ISO 8859-1 voraus.

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

Probieren Sie es online!

Erläuterung

Dies implementiert die Spezifikation ganz wörtlich:

T`'\`

Entfernen Sie Apostrophe und Backticks.

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

Teilen Sie die Zeichenfolge um Nicht-Wort-Zeichen (in Regex schließt dies auch Ziffern und Unterstriche aus) oder Unterstriche oder Positionen, die links einen Kleinbuchstaben und rechts einen Großbuchstaben und rechts einen Kleinbuchstaben enthalten. Dies würde einige leere Segmente erzeugen, wenn zwei Zeichen in einer Reihe stehen, die keine Buchstaben oder Ziffern sind oder am Anfang der Zeichenfolge eine größere Bedeutung haben. Wir werden die mit der _Option los . Hier bedeutet "Teilen", dass jedes verbleibende Teil in eine eigene Zeile gesetzt wird.

T`L`l

Wandle alles in Kleinbuchstaben um.

T`l`L`¶.

Konvertieren Sie jedes Zeichen, das nach dem Zeilenvorschub auftritt, in Großbuchstaben. Dadurch wird das erste Wort übersprungen, da kein Zeilenvorschub davor steht.

Beseitigen Sie die Zeilenvorschübe, um alles wieder zusammenzufügen.

Martin Ender
quelle
Du warst schneller als ich. Schön!
mbomb007
Diese Frage mag etwas seltsam sein, aber ... sollte ich meine Antwort posten, wenn sie kürzer ist als deine und auch in der Netzhaut? Ich habe daran gearbeitet, bevor Ihre Antwort erschien, aber dann tat es das und jetzt weiß ich nicht, ob ich es posten sollte.
Daavko
5
@daavko Sicher, poste es (ich entscheide normalerweise basierend darauf, wie unterschiedlich der Ansatz von der vorhandenen Antwort ist ... wenn es genau dasselbe ist, wenn ein Byte irgendwo abgeschnitten ist, kommentiere ich diese Antwort normalerweise nur, aber wenn es viel kürzer ist von einem anderen Ansatz, dann würde ich nur eine separate Antwort posten).
Martin Ender
2
@daavko Der Lookaround ist allerdings notwendig. Beachten Sie, dass Ihre Antwort die Großschreibung von nicht beibehält, Thingobwohl es sollte.
Martin Ender
1
@ MartinBüttner Oh ... das habe ich nicht gemerkt. Na ja, dann werde ich eine andere Herausforderung erfolgreich beantworten.
Daavko
11

Java, 198 bis 190 Bytes

+3 Byte, weil ich das vergessen habe \W+== [^a-zA-Z0-9_]+und ich muss übereinstimmen[^a-zA-Z0-9]+

-11 Bytes dank user20093 - ?:anstelle von if/else

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

Dies ist ein Lambda. Rufen Sie wie folgt an:

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

Lesbare Version:

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
quelle
1
Es ist nicht schnell ...
CalculatorFeline
2
Willkommen bei Programming Puzzles & Code Golf! Das ist eine schöne erste Antwort!
Alex A.
1
@CatsAreFluffy Was?
Katze
Wenn Sie die bedingte Anweisung (if / else) durch einen bedingten Ausdruck (? :) ersetzen, können Sie etwa 9 Bytes sparen
user902383
Ich weiß nicht, wie ich das @ user902383 - für -11 Bytes hinzugefügt - verpasst habe. Leider musste ich auch 3 addieren, um _als Token-Begrenzer zu passen .
CAD97
10

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

Danke @Neil (6 Bytes), @ETHproductions (3 Bytes) und @ edc65 (7 Bytes)

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

Entfernt Apostrophe, ersetzt Sonderzeichen / vor umgebenen Großbuchstaben und kombiniert sie mit der richtigen Groß- und Kleinschreibung. Leider toLowerCase()und toUpperCase()sind hier ärgerlich lang und schwer zu meiden ...

Mwr247
quelle
1
Ich habe an einem anderen Ansatz gearbeitet, den Ihr b.slice(i>0)Ansatz aus dem Wasser sprengt, aber in der Zwischenzeit /[A-Z]?([a-z0-9]|[0-9A-Z]{2,})+([A-Z](?![a-z]))?/gscheint mein Match-Regex von 2 Bytes mehr zu sparen als Ihr ansonsten genialer replaceAnsatz.
Neil
1
Oder ich könnte einfach 2 Bytes replacedirekt auf Ihrem speichern :replace(/[a-z](?=[A-Z][a-z])/g,'$& ')
Neil
1
Normalerweise match...mapkann ersetzt werdenreplace
edc65
1
@ edc65 Mit diesem Ansatz erhalte ich mindestens 160 Bytes: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
Auf der anderen Seite möchte ich anbieten, b=>a+=(a?b[0].toUpperCase():'')+b.slice(!!a).toLowerCase()das ich glaube, spart Ihnen weitere 4 Bytes.
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 kürzer als Perl ?! Was ist das für ein Wahnsinn?

: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

Vielen Dank an Neil, der einen unnützen Tastendruck entdeckt hat!

Türknauf
quelle
Ich kann sehen, warum der letzte :seine hat, %aber warum die Inkonsistenz in den ersten beiden?
Neil
@ Neil Bah, Muskelgedächtnis. Vielen Dank!
Türklinke
5
Lässt sich auch schlechter lesen als Perl +1
cat
Ich füge total diese zu meinen .vimrc
moopet
1
@fruglemonkey 1. :%j<cr>ist gleichwertig und kürzer. 2. Das fügt Leerzeichen zwischen Zeilen hinzu.
Türklinke
5

Mathematica 10.1, 101 Bytes

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

Verwendet das Undokumentierte ToCamelCase, das ähnlich funktioniert, Capitalizeandere Zeichen jedoch auf Kleinbuchstaben setzt.

LegionMammal978
quelle
Nicht in 10.3.0 ..
A Simmons
Ist ToCamelCase[n_,m_]:=n<>Capitalize/@mrichtig Scheint so. Und warum verwenden, Prependwenn es #~ToCamelCase~{##2}funktioniert?
CalculatorFeline
@CatsAreFluffy Das gibt mirToCamelCase::argx: ToCamelCase called with 2 arguments; 1 argument is expected.
LegionMammal978
Wie funktioniert CamelCase? Nur ToCamelCase[n_]:=""<>Capitalize/@n?
CalculatorFeline
@CatsAreFluffy, siehe dies .
LegionMammal978
5

Julia, 98 89 Bytes

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

Dies ist eine anonyme Funktion, die eine Zeichenfolge akzeptiert und eine Zeichenfolge zurückgibt. Um es aufzurufen, weisen Sie es einer Variablen zu.

Der Ansatz hier ist das gleiche wie in Doorknob der Perl Antwort : replaceApostrophe und Backticks mit dem leeren String splitin ein Array auf einem regulären Ausdruck, der die notwendigen Fälle übereinstimmt, mapdie ucfirstFunktion über das Array die ersten Buchstaben jedes Element in Großbuchstaben, joindas Array zurück in eine Zeichenfolge und lcfirstdas Ergebnis, um das erste Zeichen in Kleinbuchstaben umzuwandeln.

Alex A.
quelle
Ich mochte Julia immer als funktionaleren, interessanteren Python, aber ich hasse die endSyntax. Vielleicht benutze ich nur anonyme Funktionen für alles, dann muss ich nie end
cat
4

Perl 67 + 1 = 68 Bytes

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

Benötigt die -pFlagge und -lfür mehrzeilige:

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

Wie es funktioniert:

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.
undlrc
quelle
2

Perl, 87 80 78 Bytes

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

Byte für die -pFlagge hinzugefügt .

Zuerst verwenden wir den y///Transliterationsoperator, dum alle '`Zeichen in der Eingabe zu löschen :

y/'`//d;

Dann kommt das Fleisch des Codes:

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

(Teilen Sie die Eingabezeichenfolge $_an den entsprechenden Stellen auf, \Kund schließen Sie dabei den vorhergehenden Teil aus der tatsächlichen Übereinstimmung aus.)

          map{ucfirst lc}

(Ordnen Sie jeden geteilten Teil der Zeichenfolge zu, und schreiben Sie die gesamte Zeichenfolge in Kleinbuchstaben. Machen Sie dann das erste Zeichen der geänderten Zeichenfolge in Großbuchstaben.)

$_=join'',

(Fügen Sie eine leere Zeichenfolge hinzu und weisen Sie sie dem magischen Unterstrich zu $_, der am Ende gedruckt wird.)

Schließlich setzen wir den ersten Buchstaben in Kleinbuchstaben, indem\l wir ihn mit Regex abgleichen und in der Ersetzungszeichenfolge einen eingebauten verwenden, wodurch 2 Bytes gegenüber der vorherigen Methode eingespart werden:

lcfirst

Danke an @ MartinBüttner für 7 Bytes ( [^a-zA-Z\d]-> \W|_)!

Türknauf
quelle
1
Wie ich das beneide \K...;)
Martin Ender
2

Lua, 127 Bytes

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

Akzeptiert eine Zeichenfolge aus stdin und gibt Ergebnisse in Kamelform zurück.

Wahrscheinlich wird immer noch nach einer besseren Lösung gesucht, da sich die Speicherung in einer Variablen ineffizient anfühlt.

Aber wie auch immer, im Allgemeinen ziemlich einfach:

 z:gmatch('%w+')

Das ist die Schönheit, die mir ein bisschen Bytes erspart hat. gmatch teilt die Zeichenfolge basierend auf dem Muster: %w+das nur alphanumerische Zeichen enthält.

Danach sind es einfache Zeichenkettenoperationen. string.upper, string.lower und done.

Skyl3r
quelle
2

PHP, 145 122 133 Bytes

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

In Datei speichern, von CLI aus aufrufen.
Nimmt Eingaben von einem einzelnen Befehlszeilenargument entgegen; Entfliehen Sie gegebenenfalls Anführungszeichen und Leerzeichen.

Nervenzusammenbruch

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

lcfirsterlaubt, dies auf einen einzigen Befehl zu reduzieren, wodurch 23 Bytes gespart werden.
Das Korrigieren der Apostrophe kostet 11 Byte für den zusätzlichen Ersetzungsfall.

Titus
quelle
1

Kotlin , 160 Bytes

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

Mein Ziel war es, Scala, das andere "alternative Java", zu sein, also bin ich mit meinen Ergebnissen einigermaßen zufrieden. Ich habe den regulären Ausdruck aus der Java- Antwort gestohlen .

Teste es mit:

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
quelle
An dieser Stelle denke ich, dass jeder die optimierte Regex "ausleiht" \W|_|(?<=[a-z])(?=[A-Z][a-z])oder sie leicht modifiziert, z. [\W_]+
CAD97
Sie können einige auf Karte und Erweiterungsfunktion speichernfun String.a()=replace(Regex("['`]"),"").split(Regex("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])")).joinToString(""){it.toLowerCase().capitalize()}.decapitalize()
evtl.
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}

Prüfer:

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

Requisiten an CAD97 und Entschuldigungen an Nathan Merrill :)

froh
quelle
1
Sie können 6 Bytes einsparen, indem Sie ersetzen [^a-zA-Z0-9]+ mit [\\W_]+.
CAD97
0

C 272 Zeichen

Das C-Programm übergibt den String in Anführungszeichen als Argument 1 an camelCase. In dieser Problemstellung stecken viele Fallstricke ...

#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
quelle
Sie müssen #include<string.h>für strlen, strtokund toupper, und #include<ctype.h>für isalnum.
Mego
Ich brauchte es nicht mit gcc 3.4.4 in Cygwin. Sie müssen unter der Annahme von extern int automatisch eingebunden werden.
Cleblanc
Mit ./camel "Programming Puzzles & Code Golf"auf cygwin (kompiliert mit gcc 3.4.4) bekomme ich programmingPuzzlesCodeEGolf. Gleiche Ausgabe mit 5.3.0.
Mego
Mist. ich auch. Ich muss einen Bug beim Golfen erzeugt haben. Ich schaue es jetzt ...
Cleblanc
Das Problem war, dass ich die anderen Tokenizer-Saiten nach dem Golfen hinzugefügt und sie nicht gut genug getestet habe. Wenn Sie das '&' aus dem strtok-Aufruf entfernen, funktioniert es an diesem Eingang.
Cleblanc
0

JavaScript, 123 Bytes

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

Lesbare Version

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

Entfernen Sie die Apostrophe, schreiben Sie das erste Zeichen in Kleinbuchstaben, das letzte in Kleinbuchstaben und gruppieren Sie mehrere Großbuchstaben. Stimmen Sie mit einer Gruppe von 1 oder mehr nicht-alphanumerischen Zeichen + 1 weiteren Zeichen überein, und ersetzen Sie sie durch das zuletzt großgeschriebene Zeichen.

[r = "replace"] Trick aus der Mrw247-Lösung.

Grax32
quelle