Перетворіть підкреслення в PascalCase, тобто UpperCamelCase


28

Якщо у мене є рядок, який виглядає приблизно так:

"this_is_the_string"

Всередині bash-сценарію я хотів би перетворити його в PascalCase, тобто UpperCamelCase, щоб виглядати так:

"ThisIsTheString"

Я виявив, що перетворення на нижчийCamelCase можна зробити так:

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

На жаль, я недостатньо знайомий з регулярними виразами, щоб змінити це.


(1) Це насправді не має значення, що стосується цього питання (та відповідей, представлених до цього часу), але, FYI, \U\2вставляє знайдений текст із другої групи, перетворений на ВСІ КАПС. Порівняйте \u\2, що вставляє текст у випадку виправдання, лише з першого символу. (2) Усі приклади, наведені нижче, перекладуть "this_is_a_string" на "ThisIsAString" - це те, про що ви просили, але його важко прочитати. Можливо, ви хочете переглянути свої вимоги до особливого випадку однобуквеного слова (підрядка). … (Продовжував)
Скотт

(Продовження)… (3) Чи є у вас лише одна така рядок на рядок? І чи завжди це перший (чи єдиний ) текст у рядку? Якщо у вас є рядок, який не знаходиться на початку рядка, наведені нижче відповіді перетворять її в нижчуCamelCase. Щоб виправити, візьміть відповідь Джаніс і перейдіть (^|_)до (\<|_).
Скотт

Відповіді:


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

Замініть шаблон
(^|_)на початку рядка або після підкреслення - перша група,
([a-z])одинична маленька літера - друга група
за допомогою
\U\2верхнього обмацу другої групи в
gусьому світі.


4
Примітка: \Uрозширення GNU до POSIX.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

1
Лише зауваження, ви повинні також захопити цифри sed -r 's/(^|[-_ ]+)([0-9a-z])/\U\2/g'. Тож рядки типу "this_is_2nd_string" також працюють.
pinkeen

9

Оскільки ви використовуєте bash, якщо ви зберігали рядок у змінній, ви також можете робити це лише в оболонці:

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

${uscore//_/ }замінює все _пробілом, (....)розбиває рядок на масив, ${arr[@]^}перетворює першу букву кожного елемента у верхній регістр і потім printf %s ..друкує всі елементи один за одним.
Ви можете зберігати обкладений верблюдом рядок в іншу змінну:

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

і використовувати / використовувати його пізніше, наприклад:

printf %s\\n $ccase
ThisIsTheStringToBeConverted

Або zsh:

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

(${(s:_:)uscore})розділяє рядок на _масив, (C)використовує велику літеру кожного елемента та printf %s ...друкує всі елементи один за одним ..
Щоб зберегти його в іншій змінній, яку ви можете використовувати (j::)для приєднання елементів:

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

і використовувати / використовувати його пізніше:

printf %s\\n $ccase
ThisIsTheStringToBeConverted

8

Ось спосіб Perl:

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

Він може мати рядки довільної довжини:

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

Він буде відповідати будь-якому символу ( .), який з’являється після початку рядка або підкреслення ( (^|_)), і замінить його верхнім регістром себе ( uc($&)). Це $&спеціальна змінна, яка містить те, що було щойно узгоджено. В eкінці дозволу s///geможна використовувати вирази ( uc()функція в даному випадку) в рамках підстановки і gзмушує її замінити всі входження в рядку. Друга заміна знімає підкреслення.


Говорячи про perl, існує також модуль perl String :: CamelCase, який "підкреслив" підкреслений текст.
don_crissti

@don_crissti ooh, ідеально підходить для цього. Спасибі.
terdon

Коротше Perl:perl -pe 's/(^|_)([a-z])/uc($2)/ge'
Ісаак

6

Не обов’язково представляти весь рядок у звичайному збігу виразів - sed має /gмодифікатор, який дозволяє переходити через декілька збігів та замінювати кожне з них:

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

Перший регулярний вираз _\([a-z]\)- кожна буква після підкреслення; другий відповідає першій букві в рядку.


3

Я відповідаю лише на цю відповідь, тому що вона коротша і простіша, ніж будь-яка інша поки що.

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

У ній написано: "upcase", персонаж, що слідує за a _або на початку. Букви, які не бувають, не будуть змінені, оскільки у них немає справи.


1
"Все повинно бути максимально простим, але не простішим". - Альберт Ейнштейн. Це не рівнозначно іншим відповідям; Ваша відповідь перетворить "FOO_BAR" у "FOOBAR", а інші відповіді залишить це в спокої.
Скотт

@scott Так, я не думав про це.
ctrl-alt-delor

1
@Scott Це не бажана поведінка? Я думаю, що в ідеалі це повинно стати, FooBarале підкреслення слід усунути відповідно до інструкцій. Як я розумію інструкцію все одно.
terdon

2
(Протяг)… (3) Я думаю, що дещо зрозуміло, що дух питання полягає в тому, щоб перетворити рядок так, щоб розриви слів, позначені підкресленнями ( _), замість цього позначалися переходами регістру. Зважаючи на те, що "FOO_BAR" → "FOOBAR" явно неправильно (оскільки він відкидає інформацію про перелом слова), хоча "FOO_BAR" → "FooBar" може бути правильним. (4) Аналогічно, відображення, яке спричиняє зіткнення, здається, суперечить духу питання. Наприклад, я вважаю, що відповідь, яка перетворює "DO_SPORTS" і "DOS_PORTS" на ту саму ціль, є помилковою.
Скотт

1
(Продовжуй знову)… (5) У дусі не спричиняти зіткнень, мені здається, що "foo_bar" і "FOO_BAR" не повинні збігатися з одним і тим же, тому я заперечую проти "FOO_BAR" → "FooBar" . (6) Я думаю, що більша проблема - це простори імен. Я не програмував у Паскалі з моменту, коли Блейз був живий, але в C / C ++, за умовою, ідентифікатори, які в основному знаходяться в нижньому регістрі (включаючи snake_case та CamelCase), як правило, є доменом компілятора, тоді як ідентифікатори у верхньому регістрі - це домен попереднього процесора. Тому я вважаю, що ОП не хотів розглядати ідентифікатори ALL_CAPS.
Скотт

1

У перл:

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

Це також можливість i18n:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.