Converti il ​​trattino basso in PascalCase, ovvero UpperCamelCase


28

Se ho una stringa simile a questa:

"this_is_the_string"

All'interno di uno script bash, vorrei convertirlo in PascalCase, ovvero UpperCamelCase per assomigliare a questo:

"ThisIsTheString"

Ho scoperto che la conversione in lowerCamelCase può essere fatta in questo modo:

"this_is_the_string" | sed -r 's/([a-z]+)_([a-z])([a-z]+)/\1\U\2\L\3/'

Sfortunatamente non ho abbastanza familiarità con le regex per modificarlo.


(1) Questo non ha molta importanza, per quanto riguarda questa domanda (e le risposte presentate finora), ma, FYI, \U\2inserisce il testo trovato dal secondo gruppo, convertito in TUTTI MAIUSCOLI. Confronta con \u\2, che inserisce il testo in maiuscolo, con solo il primo carattere in maiuscolo. (2) Tutti gli esempi riportati di seguito tradurranno "this_is_a_string" in "ThisIsAString" - che è quello che hai chiesto, ma è leggermente difficile da leggere. Potresti voler rivedere i tuoi requisiti per il caso speciale di una parola di una lettera (sottostringa). ... (proseguendo)
Scott,

(Proseguendo) ... (3) Hai solo una di queste stringhe per riga? Ed è sempre il primo (o unico ) testo sulla riga? Se hai una stringa che non è all'inizio della riga, le risposte seguenti la convertiranno in lowerCamelCase. Per risolvere, prendi la risposta di Janis e (^|_)passa a (\<|_).
Scott,

Risposte:


44
$ echo "this_is_the_string" | sed -r 's/(^|_)([a-z])/\U\2/g'            
ThisIsTheString

Reticolo sostituto
(^|_)all'inizio della stringa o dopo un trattino - primo gruppo
([a-z])singolo lettera minuscola - secondo gruppo
da
\U\2maiuscolo secondo gruppo
gglobale.


4
Nota: \Uè un'estensione GNU per POSIX.
Ciro Santilli 19 改造 中心 法轮功 六四 事件

1
Solo una nota, dovresti anche catturare numeri sed -r 's/(^|[-_ ]+)([0-9a-z])/\U\2/g'. Quindi funzionano anche stringhe come "this_is_2nd_string" .
Pinkeen

9

Dal momento che stai usando bash, se hai archiviato la stringa in una variabile, puoi anche farlo solo con shell:

uscore="this_is_the_string_to_be_converted"
arr=(${uscore//_/ })
printf %s "${arr[@]^}"
ThisIsTheStringToBeConverted

${uscore//_/ }sostituisce tutto _con spazio, (....)divide la stringa in un array, ${arr[@]^}converte la prima lettera di ciascun elemento in maiuscolo e quindi printf %s ..stampa tutti gli elementi uno dopo l'altro.
Puoi memorizzare la stringa incapsulata nel cammello in un'altra variabile:

printf -v ccase %s "${arr[@]^}"

e utilizzarlo / riutilizzarlo in seguito, ad esempio:

printf %s\\n $ccase
ThisIsTheStringToBeConverted

Oppure, con zsh:

uscore="this_is_the_string_to_be_converted"
arr=(${(s:_:)uscore})
printf %s "${(C)arr}"
ThisIsTheStringToBeConverted

(${(s:_:)uscore})divide la stringa _in un array, rende (C)maiuscola la prima lettera di ogni elemento e printf %s ...stampa uno dopo l'altro tutti gli elementi.
Per memorizzarlo in un'altra variabile è possibile utilizzare (j::)per unire gli elementi:

ccase=${(j::)${(C)arr}}

e utilizzarlo / riutilizzarlo in seguito:

printf %s\\n $ccase
ThisIsTheStringToBeConverted

8

Ecco un modo Perl:

$ echo "this_is_the_string" | perl -pe 's/(^|_)./uc($&)/ge;s/_//g'
ThisIsTheString

Può gestire stringhe di lunghezza arbitraria:

$ echo "here_is_another_larger_string_with_more_parts" | 
    perl -pe 's/(^|_)./uc($&)/ge;s/_//g'
HereIsAnotherLargerStringWithMoreParts

Corrisponderà a qualsiasi carattere ( .) che viene dopo l'inizio della stringa o un trattino basso ( (^|_)) e lo sostituirà con la versione maiuscola di se stesso ( uc($&)). Il $&è una variabile speciale che contiene tutto ciò che è stato appena abbinato. Il ealla fine di s///geconsente l'uso di espressioni (la uc()funzione in questo caso) all'interno della sostituzione e le gfa sostituire tutte le occorrenze nella riga. La seconda sostituzione rimuove i caratteri di sottolineatura.


Parlando di perl, c'è anche un modulo perl String :: CamelCase che "camelizza" il testo sottolineato.
don_crissti,

@don_crissti ooh, sembra perfetto per questo. Grazie.
terdon

Perl più breve:perl -pe 's/(^|_)([a-z])/uc($2)/ge'
Isaac,

6

Non è necessario rappresentare l' intera stringa in una corrispondenza di espressione regolare - sed ha il /gmodificatore che ti permette di camminare su più partite e sostituirle ognuna:

echo "this_is_the_string" | sed 's/_\([a-z]\)/\U\1/g;s/^\([a-z]\)/\U\1/g'

La prima regex è _\([a-z]\)- ogni lettera dopo il trattino basso; la seconda corrisponde alla prima lettera di una stringa.


3

Ho inserito questa risposta solo perché è più breve e più semplice di qualsiasi altra finora.

sed -re "s~(^|_)(.)~\U\2~g"

Dice: upcase, il personaggio che segue a _o l'inizio. Le non lettere non verranno modificate, in quanto non hanno alcun caso.


1
"Tutto dovrebbe essere reso il più semplice possibile, ma non più semplice." - Albert Einstein. Questo non è equivalente alle altre risposte; la tua risposta convertirà "FOO_BAR" in "FOOBAR", mentre le altre risposte la lasceranno sola.
Scott,

@scott Ah sì, non ci ho pensato.
ctrl-alt-delor,

1
@Scott Non è questo il comportamento desiderato? Immagino che idealmente dovrebbe essere, FooBarma il carattere di sottolineatura dovrebbe essere rimosso secondo le istruzioni. Come capisco le istruzioni comunque.
terdon

2
(Continua) ... (3) Penso che sia in qualche modo chiaro che lo spirito della domanda è trasformare una stringa in modo che le interruzioni di parole indicate da caratteri di sottolineatura ( _) siano invece indicate da transizioni di maiuscole. Dato che, "FOO_BAR" → "FOOBAR" è chiaramente errato (poiché ignora le informazioni di interruzione di parola), sebbene "FOO_BAR" → "FooBar" potrebbe essere corretto. (4) Allo stesso modo, una mappatura che provoca collisioni sembra essere contraria allo spirito della questione. Ad esempio, credo che una risposta che converta "DO_SPORTS" e "DOS_PORTS" nella stessa destinazione sia errata.
Scott,

1
(Continua ancora)… (5) Nello spirito di non provocare collisioni, mi sembra che “foo_bar” e “FOO_BAR” non debbano essere mappati sulla stessa cosa, quindi mi oppongo a “FOO_BAR” → “FooBar” . (6) Penso che il problema più grande siano gli spazi dei nomi. Non ho programmato in Pascal da quando Blaise era vivo, ma in C / C ++, per convenzione, gli identificatori che sono principalmente in minuscolo (per includere snake_case e CamelCase) sono generalmente il dominio del compilatore, mentre gli identificatori in maiuscolo sono il dominio del pre-processore. Ecco perché penso che l'OP non volesse prendere in considerazione gli identificatori ALL_CAPS.
Scott,

1

In perl:

$ echo 'alert_beer_core_hemp' | perl -pe 's/(?:\b|_)(\p{Ll})/\u$1/g'
AlertBeerCoreHemp

Questo è anche in grado di i18n:

$ echo 'алерт_беер_коре_хемп' | perl -CIO -pe 's/(?:\b|_)(\p{Ll})/\u$1/g'
АлертБеерКореХемп

0

L'ho fatto in questo modo:

echo "this_is_the_string" | sed -r 's/(\<|_)([[:alnum:]])/\U\2/g'

e ottenuto questo risultato:

ThisIsTheString
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.