Chuyển đổi gạch dưới thành PascalCase, tức là UpperCamelCase


28

Nếu tôi có một chuỗi trông như thế này:

"this_is_the_string"

Trong tập lệnh bash, tôi muốn chuyển đổi nó thành PascalCase, tức là UpperCamelCase để trông như thế này:

"ThisIsTheString"

Tôi thấy rằng việc chuyển đổi sang lowCamelCase có thể được thực hiện như thế này:

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

Thật không may, tôi không đủ quen thuộc với regexes để sửa đổi điều này.


(1) Điều này không thực sự quan trọng, theo như câu hỏi này (và các câu trả lời được trình bày cho đến nay) có liên quan, nhưng, FYI, \U\2chèn văn bản tìm thấy từ nhóm thứ hai, được chuyển đổi thành TẤT CẢ CAPS. So sánh với \u\2, chèn văn bản trong trường hợp Câu, chỉ có ký tự đầu tiên được viết hoa. (2) Tất cả các ví dụ được đưa ra dưới đây sẽ dịch chuyển this this_is_a_opes và thành This ThisASASringring - đây là những gì bạn yêu cầu, nhưng hơi khó đọc. Bạn có thể muốn sửa đổi các yêu cầu của mình cho trường hợp đặc biệt của một từ một chữ cái (chuỗi con). Tiết (Cont'd)
Scott

(Tiếp theo) Nhiều (3) Bạn chỉ có một chuỗi như vậy trên mỗi dòng? Và nó luôn luôn là văn bản đầu tiên (hoặc duy nhất ) trên dòng? Nếu bạn có một chuỗi không nằm ở đầu dòng, các câu trả lời dưới đây sẽ chuyển đổi nó thành lowCamelCase. Để khắc phục, hãy lấy câu trả lời của Janis và đổi (^|_)thành (\<|_).
Scott

Câu trả lời:


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

Mẫu thay thế
(^|_)ở đầu chuỗi hoặc sau dấu gạch dưới - chữ cái viết thường
([a-z])đơn nhóm thứ nhất - nhóm thứ hai
bằng cách vượt qua
\U\2nhóm thứ hai
gtrên toàn cầu.


4
Lưu ý: \Ulà phần mở rộng GNU cho POSIX.
Ciro Santilli 新疆 心 心

1
Chỉ cần một lưu ý, bạn cũng nên nắm bắt số sed -r 's/(^|[-_ ]+)([0-9a-z])/\U\2/g'. Vì vậy, các chuỗi như "this_is_2nd_opes" cũng hoạt động.
pinkeen

9

Vì bạn đang sử dụng bash, nếu bạn lưu trữ chuỗi của mình trong một biến, bạn cũng có thể thực hiện nó chỉ ở dạng vỏ:

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

${uscore//_/ }thay thế tất cả _bằng khoảng (....)trắng , chia chuỗi thành một mảng, ${arr[@]^}chuyển đổi chữ cái đầu tiên của mỗi phần tử thành chữ hoa và sau đó printf %s ..in tất cả các phần tử lần lượt.
Bạn có thể lưu trữ chuỗi vỏ lạc đà vào một biến khác:

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

và sử dụng / tái sử dụng nó sau, vd:

printf %s\\n $ccase
ThisIsTheStringToBeConverted

Hoặc, với zsh:

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

(${(s:_:)uscore})chia chuỗi trên _thành một mảng, (C)viết hoa chữ cái đầu tiên của mỗi phần tử và printf %s ...in tất cả các phần tử lần lượt ..
Để lưu nó trong một biến khác, bạn có thể sử dụng (j::)để nối các phần tử:

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

và sử dụng / tái sử dụng nó sau:

printf %s\\n $ccase
ThisIsTheStringToBeConverted

8

Đây là một cách Perl:

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

Nó có thể xử lý các chuỗi có độ dài tùy ý:

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

Nó sẽ khớp với bất kỳ ký tự nào ( .) xuất hiện sau khi bắt đầu chuỗi hoặc dấu gạch dưới ( (^|_)) và thay thế nó bằng phiên bản chữ hoa của chính nó ( uc($&)). Đây $&là một biến đặc biệt có chứa bất cứ thứ gì vừa khớp. Ở ecuối của s///gecho phép sử dụng các biểu thức ( uc()hàm trong trường hợp này) trong phạm vi thay thế và glàm cho nó thay thế tất cả các lần xuất hiện trong dòng. Sự thay thế thứ hai loại bỏ các dấu gạch dưới.


Nói về perl, cũng có một mô-đun perl String :: CamelCase "camelizes" văn bản chưa được ký.
don_crissti

@don_crissti ooh, âm thanh hoàn hảo cho việc này. Cảm ơn.
terdon

Perl ngắn hơn:perl -pe 's/(^|_)([a-z])/uc($2)/ge'
Isaac

6

Không cần thiết phải biểu diễn toàn bộ chuỗi trong một kết hợp biểu thức chính quy - sed có công cụ /gsửa đổi cho phép bạn đi qua nhiều kết quả khớp và thay thế từng chuỗi:

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

Regex đầu tiên là _\([a-z]\)- mỗi chữ cái sau dấu gạch dưới; cái thứ hai khớp với chữ cái đầu tiên trong một chuỗi.


3

Tôi chỉ đưa ra câu trả lời này vì nó ngắn hơn và đơn giản hơn bất kỳ câu trả lời nào khác cho đến nay.

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

Nó nói: upcase, ký tự theo a _hoặc bắt đầu. Không thư sẽ không được thay đổi, vì họ không có trường hợp.


1
"Mọi thứ nên được làm đơn giản nhất có thể, nhưng không đơn giản hơn." - Albert Einstein. Điều này không tương đương với các câu trả lời khác; câu trả lời của bạn sẽ chuyển đổi "FOO_BAR" thành "FOOebar", trong khi các câu trả lời khác sẽ để yên.
Scott

@scott À đúng rồi, tôi không nghĩ về điều đó.
ctrl-alt-delor

1
@Scott Không phải đó là hành vi mong muốn sao? Tôi đoán rằng lý tưởng, nó sẽ trở thành FooBarnhưng gạch dưới nên được loại bỏ theo hướng dẫn. Theo tôi hiểu các hướng dẫn nào.
terdon

2
(Tiếp theo) (3) Tôi nghĩ rằng phần nào rõ ràng rằng tinh thần của câu hỏi là biến đổi một chuỗi sao cho các ngắt từ được biểu thị bằng dấu gạch dưới ( _) thay vào đó được biểu thị bằng các chuyển đổi trường hợp. Cho rằng, FOO_BAR trực tiếp → → FOObarAR rõ ràng là sai (vì nó loại bỏ thông tin ngắt từ), mặc dù, F F (4) Tương tự, một ánh xạ gây ra va chạm dường như trái với tinh thần của câu hỏi. Ví dụ, tôi tin rằng một câu trả lời chuyển đổi DẠNG DỪNG ĐỔI VÀ ĐỔI CÁCH DẠNG CÁCH ĐỔI cùng một mục tiêu là sai.
Scott

1
(Tiếp tục lại), (5) Với tinh thần không gây ra va chạm, đối với tôi, dường như rằng Foo_bar, và FOO_BAR không nên ánh xạ tới điều tương tự, vì vậy tôi phản đối với FOO_BAR . (6) Tôi nghĩ vấn đề lớn hơn là không gian tên. Tôi đã không được lập trình trong Pascal kể từ khi Blaise còn sống, nhưng trong C / C ++, theo quy ước, các định danh chủ yếu ở dạng chữ thường (bao gồm cả sn_case và CamelCase) nói chung là miền của trình biên dịch, trong khi các định danh trong chữ hoa miền của bộ xử lý trước. Vì vậy, đó là lý do tại sao tôi nghĩ rằng OP không muốn các định danh ALL_CAPS được xem xét.
Scott

1

Trong perl:

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

Đây cũng là i18n có thể:

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

0

Tôi đã làm theo cách này:

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

và nhận được kết quả này:

ThisIsTheString
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.