CamelCase! Itulah namanya! Aku menyukainya! Terimakasih banyak!
Matias Nino
19
Sebenarnya camelCase memiliki huruf kecil di depannya. Yang Anda maksud di sini adalah PascalCase.
Drew Noakes
12
... dan jika Anda merujuk pada sesuatu yang bisa berupa "kasus unta" atau "kasus pascal", ini disebut "intercapped"
Chris
Tidak membagi "Take5" yang akan gagal dalam kasus penggunaan saya
PandaWood
1
@PandaWood Digit tidak ada dalam pertanyaan, jadi jawaban saya tidak memperhitungkannya. Saya telah menambahkan varian pola yang memperhitungkan digit.
Sejauh ini, ini adalah solusi terbaik, tetapi Anda perlu menggunakan \\ B untuk mengkompilasi. Jika tidak, kompilator mencoba memperlakukan \ B sebagai urutan pelolosan.
Ferruccio
Solusi bagus. Adakah yang bisa memikirkan alasan mengapa ini seharusnya tidak menjadi jawaban yang diterima? Apakah itu kurang mampu atau kurang berkinerja?
Drew Noakes
8
Yang satu ini memperlakukan huruf besar yang berurutan sebagai kata yang terpisah (misalnya ANZAC terdiri dari 5 kata) sedangkan jawaban MizardX memperlakukannya (dengan benar IMHO) sebagai satu kata.
Ray
2
@ Ray, saya berpendapat bahwa "ANZAC" harus ditulis sebagai "Anzac" untuk dianggap sebagai kata kasus pascal karena ini bukan kasus bahasa Inggris.
Sam
1
@ Neox, seharusnya dalam bahasa Inggris, tetapi ini bukan akronim-case atau normal-english-case; itu dibatasi huruf besar. Jika teks sumber harus menggunakan huruf besar dengan cara yang sama seperti dalam bahasa Inggris normal, maka huruf lain juga tidak boleh menggunakan huruf besar. Misalnya, mengapa "i" dalam "adalah" menggunakan huruf besar agar sesuai dengan format yang dipisahkan huruf kapital tetapi bukan "NZAC" dalam "ANZAC"? Sebenarnya, jika Anda menafsirkan "ANZAC" sebagai huruf besar-kecil maka itu adalah 5 kata, satu untuk setiap huruf.
Sam
19
Jawaban yang bagus, MizardX! Saya mengubahnya sedikit untuk memperlakukan angka sebagai kata terpisah, sehingga "AddressLine1" akan menjadi "Address Line 1" bukan "Address Line1":
Tambahan yang bagus! Saya menduga tidak sedikit orang akan terkejut dengan jawaban yang diterima penanganan bilangan dalam string. :)
Jordan Grey
Saya tahu sudah hampir 8 tahun sejak Anda memposting ini, tetapi ini juga berfungsi dengan baik untuk saya. :) Angka-angka itu membuat saya tersandung pada awalnya.
Michael Armes
Satu-satunya jawaban yang lolos dari 2 tes pencilan saya: "Take5" -> "Take 5", "PublisherID" -> "Publisher ID". Saya ingin memberi
suara positif
18
Hanya untuk sedikit variasi ... Berikut adalah metode ekstensi yang tidak menggunakan regex.
publicstaticclassCamelSpaceExtensions{publicstaticstringSpaceCamelCase(thisString input){returnnewstring(Enumerable.Concat(
input.Take(1),// No space before initial capInsertSpacesBeforeCaps(input.Skip(1))).ToArray());}privatestaticIEnumerable<char>InsertSpacesBeforeCaps(IEnumerable<char> input){foreach(char c in input){if(char.IsUpper(c)){yieldreturn' ';}yieldreturn c;}}}
Untuk menghindari penggunaan Trim (), sebelum foreach saya meletakkan: int counter = -1. di dalam, tambahkan counter ++. ubah centang ke: if (char.IsUpper (c) && counter> 0)
Outside the Box Developer
Ini menyisipkan spasi sebelum karakter pertama.
Zar Shardan
Saya telah mengambil kebebasan untuk memperbaiki masalah yang ditunjukkan oleh @ZarShardan. Jangan ragu untuk memutar kembali atau mengedit perbaikan Anda sendiri jika Anda tidak menyukai perubahan tersebut.
jpmc26
Dapatkah ini ditingkatkan untuk menangani singkatan misalnya dengan menambahkan spasi sebelum huruf besar terakhir dalam serangkaian huruf besar misalnya BOEForecast => BOE Forecast
Nepaluz
11
Berikan komentar luar biasa Wagner:
Dim s AsString=RegularExpressions.Regex.Replace("ThisIsMyCapsDelimitedString","([A-Z])"," $1")
Poin bagus ... Jangan ragu untuk memasukkan .substring (), .trimstart (), .trim (), .remove (), dll. Sesuai pilihan Anda. :)
Pseudo Masochist
9
Saya membutuhkan solusi yang mendukung akronim dan angka. Solusi berbasis Regex ini memperlakukan pola berikut sebagai "kata" individual:
Huruf kapital diikuti dengan huruf kecil
Urutan angka berurutan
Huruf kapital berturut-turut (diartikan sebagai akronim) - kata baru dapat dimulai menggunakan huruf besar terakhir, misalnya HTMLGuide => "Panduan HTML", "TheATeam" => "Tim A"
Pendekatan yang lebih mudah dibaca mungkin lebih baik:
usingSystem.Text.RegularExpressions;namespaceDemo{publicclassIntercappedStringHelper{privatestaticreadonlyRegexSeparatorRegex;staticIntercappedStringHelper(){conststring pattern =@"
(?<!^) # Not start
(
# Digit, not preceded by another digit
(?<!\d)\d
|
# Upper-case letter, followed by lower-case letter if
# preceded by another upper-case letter, e.g. 'G' in HTMLGuide
(?(?<=[A-Z])[A-Z](?=[a-z])|[A-Z])
)";var options =RegexOptions.IgnorePatternWhitespace|RegexOptions.Compiled;SeparatorRegex=newRegex(pattern, options);}publicstaticstringSeparateWords(stringvalue,string separator =" "){returnSeparatorRegex.Replace(value, separator +"$1");}}}
+1 untuk menjelaskan regex dan membuatnya dapat dibaca. Dan saya belajar sesuatu yang baru. Ada mode spasi bebas dan komentar di .NET Regex. Terima kasih!
Felix Keil
4
Untuk variasi lainnya, menggunakan objek C # biasa, berikut ini menghasilkan output yang sama seperti ekspresi reguler @ MizardX yang sangat baik.
publicstringFromCamelCase(string camel){// omitted checking camel for nullStringBuilder sb =newStringBuilder();int upperCaseRun =0;foreach(char c in camel){// append a space only if we're not at the start// and we're not already in an all caps string.if(char.IsUpper(c)){if(upperCaseRun ==0&& sb.Length!=0){
sb.Append(' ');}
upperCaseRun++;}elseif(char.IsLower(c)){if(upperCaseRun >1)//The first new word will also be capitalized.{
sb.Insert(sb.Length-1,' ');}
upperCaseRun =0;}else{
upperCaseRun =0;}
sb.Append(c);}return sb.ToString();}
Saya tahu akan ada cara RegEx yang mudah ... Saya harus mulai lebih sering menggunakannya.
Max Schmeling
1
Bukan guru regex tapi apa yang terjadi dengan "HeresAWTFString"?
Nick
1
Anda mendapatkan "Heres AWTF String" tapi itulah yang ditanyakan Matias Nino dalam pertanyaan tersebut.
Max Schmeling
Ya, dia perlu menambahkan bahwa "beberapa ibu kota yang berdekatan dibiarkan sendiri". Yang cukup jelas diperlukan dalam banyak kasus misalnya "PublisherID" di sini menuju ke "Publisher I D" yang sangat buruk
PandaWood
2
Regex sekitar 10-12 kali lebih lambat dari loop sederhana:
publicstaticstringCamelCaseToSpaceSeparated(thisstring str){if(string.IsNullOrEmpty(str)){return str;}var res =newStringBuilder();
res.Append(str[0]);for(var i =1; i < str.Length; i++){if(char.IsUpper(str[i])){
res.Append(' ');}
res.Append(str[i]);}return res.ToString();}
Saya memodifikasi Anda, tetapi orang-orang biasanya akan lebih baik jika tidak dimulai dengan "naif".
MusiGenesis
Saya tidak berpikir itu adalah pukulan keras. Dalam konteks ini, naif biasanya berarti jelas atau sederhana (yaitu belum tentu solusi terbaik). Tidak ada niat menghina.
Ferruccio
0
Mungkin ada solusi yang lebih elegan, tetapi inilah yang saya temukan di luar kepala saya:
string myString ="ThisIsMyCapsDelimitedString";for(int i =1; i < myString.Length; i++){if(myString[i].ToString().ToUpper()== myString[i].ToString()){
myString = myString.Insert(i," ");
i++;}}
privatestaticStringBuilder camelCaseToRegular(string i_String){StringBuilder output =newStringBuilder();int i =0;foreach(char character in i_String){if(character <='Z'&& character >='A'&& i >0){
output.Append(" ");}
output.Append(character);
i++;}return output;}
/// <summary>/// Get the words in a code <paramref name="identifier"/>./// </summary>/// <param name="identifier">The code <paramref name="identifier"/></param> to extract words from.publicstaticstring[]GetWords(thisstring identifier){Contract.Ensures(Contract.Result<string[]>()!=null,"returned array of string is not null but can be empty");if(identifier ==null){returnnewstring[0];}if(identifier.Length==0){returnnewstring[0];}constint MIN_WORD_LENGTH =2;// Ignore one letter or one digit wordsvar length = identifier.Length;var list =newList<string>(1+ length/2);// Set capacity, not possible more words since we discard one char wordsvar sb =newStringBuilder();CharKind cKindCurrent =GetCharKind(identifier[0]);// length is not zero hereCharKind cKindNext = length ==1?CharKind.End:GetCharKind(identifier[1]);for(var i =0; i < length; i++){var c = identifier[i];CharKind cKindNextNext =(i >= length -2)?CharKind.End:GetCharKind(identifier[i +2]);// Process cKindCurrentswitch(cKindCurrent){caseCharKind.Digit:caseCharKind.LowerCaseLetter:
sb.Append(c);// Append digit or lowerCaseLetter to sbif(cKindNext ==CharKind.UpperCaseLetter){goto TURN_SB_INTO_WORD;// Finish word if next char is upper}goto CHAR_PROCESSED;caseCharKind.Other:goto TURN_SB_INTO_WORD;default:// charCurrent is never Start or EndDebug.Assert(cKindCurrent ==CharKind.UpperCaseLetter);break;}// Here cKindCurrent is UpperCaseLetter// Append UpperCaseLetter to sb anyway
sb.Append(c);switch(cKindNext){default:goto CHAR_PROCESSED;caseCharKind.UpperCaseLetter:// "SimpleHTTPServer" when we are at 'P' we need to see that NextNext is 'e' to get the word!if(cKindNextNext ==CharKind.LowerCaseLetter){goto TURN_SB_INTO_WORD;}goto CHAR_PROCESSED;caseCharKind.End:caseCharKind.Other:break;// goto TURN_SB_INTO_WORD;}//------------------------------------------------
TURN_SB_INTO_WORD:string word = sb.ToString();
sb.Length=0;if(word.Length>= MIN_WORD_LENGTH){
list.Add(word);}
CHAR_PROCESSED:// Shift left for next iteration!
cKindCurrent = cKindNext;
cKindNext = cKindNextNext;}string lastWord = sb.ToString();if(lastWord.Length>= MIN_WORD_LENGTH){
list.Add(lastWord);}return list.ToArray();}privatestaticCharKindGetCharKind(char c){if(char.IsDigit(c)){returnCharKind.Digit;}if(char.IsLetter(c)){if(char.IsUpper(c)){returnCharKind.UpperCaseLetter;}Debug.Assert(char.IsLower(c));returnCharKind.LowerCaseLetter;}returnCharKind.Other;}enumCharKind{End,// For end of stringDigit,UpperCaseLetter,LowerCaseLetter,Other}
Tes:
[TestCase((string)null,"")][TestCase("","")]// Ignore one letter or one digit words[TestCase("A","")][TestCase("4","")][TestCase("_","")][TestCase("Word_m_Field","Word Field")][TestCase("Word_4_Field","Word Field")][TestCase("a4","a4")][TestCase("ABC","ABC")][TestCase("abc","abc")][TestCase("AbCd","Ab Cd")][TestCase("AbcCde","Abc Cde")][TestCase("ABCCde","ABC Cde")][TestCase("Abc42Cde","Abc42 Cde")][TestCase("Abc42cde","Abc42cde")][TestCase("ABC42Cde","ABC42 Cde")][TestCase("42ABC","42 ABC")][TestCase("42abc","42abc")][TestCase("abc_cde","abc cde")][TestCase("Abc_Cde","Abc Cde")][TestCase("_Abc__Cde_","Abc Cde")][TestCase("ABC_CDE_FGH","ABC CDE FGH")][TestCase("ABC CDE FGH","ABC CDE FGH")]// Should not happend (white char) anything that is not a letter/digit/'_' is considered as a separator[TestCase("ABC,CDE;FGH","ABC CDE FGH")]// Should not happend (,;) anything that is not a letter/digit/'_' is considered as a separator[TestCase("abc<cde","abc cde")][TestCase("abc<>cde","abc cde")][TestCase("abc<D>cde","abc cde")]// Ignore one letter or one digit words[TestCase("abc<Da>cde","abc Da cde")][TestCase("abc<cde>","abc cde")][TestCase("SimpleHTTPServer","Simple HTTP Server")][TestCase("SimpleHTTPS2erver","Simple HTTPS2erver")][TestCase("camelCase","camel Case")][TestCase("m_Field","Field")][TestCase("mm_Field","mm Field")]publicvoidTest_GetWords(string identifier,string expectedWordsStr){var expectedWords = expectedWordsStr.Split(' ');if(identifier ==null|| identifier.Length<=1){
expectedWords =newstring[0];}var words = identifier.GetWords();Assert.IsTrue(words.SequenceEqual(expectedWords));}
Solusi sederhana, yang harus urutan besarnya lebih cepat daripada solusi regex (berdasarkan tes yang saya lakukan terhadap solusi teratas di utas ini), terutama saat ukuran string input bertambah:
string s1 ="ThisIsATestStringAbcDefGhiJklMnoPqrStuVwxYz";string s2;StringBuilder sb =newStringBuilder();foreach(char c in s1)
sb.Append(char.IsUpper(c)?" "+ c.ToString(): c.ToString());
s2 = sb.ToString();
Regex.Replace(s, "([A-Z0-9]+)", " $1").Trim()
. Dan jika Anda ingin membagi setiap huruf kapital, hapus saja plusnya.Jawaban:
Saya membuat ini beberapa waktu lalu. Ini cocok dengan setiap komponen dari nama CamelCase.
Sebagai contoh:
Untuk mengubahnya menjadi hanya menyisipkan spasi di antara kata-kata:
Jika Anda perlu menangani angka:
sumber
sumber
Jawaban yang bagus, MizardX! Saya mengubahnya sedikit untuk memperlakukan angka sebagai kata terpisah, sehingga "AddressLine1" akan menjadi "Address Line 1" bukan "Address Line1":
sumber
Hanya untuk sedikit variasi ... Berikut adalah metode ekstensi yang tidak menggunakan regex.
sumber
Berikan komentar luar biasa Wagner:
sumber
Saya membutuhkan solusi yang mendukung akronim dan angka. Solusi berbasis Regex ini memperlakukan pola berikut sebagai "kata" individual:
Anda bisa melakukannya sebagai satu baris:
Pendekatan yang lebih mudah dibaca mungkin lebih baik:
Berikut ekstrak dari tes (XUnit):
sumber
Untuk variasi lainnya, menggunakan objek C # biasa, berikut ini menghasilkan output yang sama seperti ekspresi reguler @ MizardX yang sangat baik.
sumber
Di bawah ini adalah prototipe yang mengubah yang berikut ini menjadi Kasus Judul:
Jelas Anda hanya membutuhkan metode "ToTitleCase" sendiri.
Konsol keluarnya adalah sebagai berikut:
Entri Blog Dirujuk
sumber
sumber
Regex sekitar 10-12 kali lebih lambat dari loop sederhana:
sumber
Solusi regex naif. Tidak akan menangani O'Conner, dan menambahkan spasi di awal string juga.
sumber
Mungkin ada solusi yang lebih elegan, tetapi inilah yang saya temukan di luar kepala saya:
sumber
Coba gunakan
Hasilnya akan cocok untuk campuran alfabet dengan angka
sumber
Menerapkan kode psudo dari: https://stackoverflow.com/a/5796394/4279201
sumber
Untuk mencocokkan antara Kategori Unicode Huruf non-huruf besar dan Huruf Besar :
(?<=\P{Lu})(?=\p{Lu})
sumber
Impl prosedural dan cepat:
Tes:
sumber
Solusi sederhana, yang harus urutan besarnya lebih cepat daripada solusi regex (berdasarkan tes yang saya lakukan terhadap solusi teratas di utas ini), terutama saat ukuran string input bertambah:
sumber