我在尋找一種簡單,有效的方式轉換爲字符串首字母大寫強調符號(即MyClassName - > my_class_name)和目的C.首字母大寫,下劃線和回用Objective-C
再次回到我目前的解決方案涉及很多rangeOfString
,characterAtIndex
和對NSMutableStrings的操作,並且就像地獄一樣簡單醜陋:)似乎必須有更好的解決方案,但我不確定它是什麼。
我寧願不爲這個用例導入一個正則表達式庫,儘管如果所有其他的失敗都是這樣。
我在尋找一種簡單,有效的方式轉換爲字符串首字母大寫強調符號(即MyClassName - > my_class_name)和目的C.首字母大寫,下劃線和回用Objective-C
再次回到我目前的解決方案涉及很多rangeOfString
,characterAtIndex
和對NSMutableStrings的操作,並且就像地獄一樣簡單醜陋:)似乎必須有更好的解決方案,但我不確定它是什麼。
我寧願不爲這個用例導入一個正則表達式庫,儘管如果所有其他的失敗都是這樣。
Chris對RegexKitLite的建議很好。這是一個很好的工具包,但這可以通過NSScanner輕鬆完成。在+uppercaseLetterCharacterSet
和+lowercaseLetterCharacterSet
之間交替使用-scanCharactersFromSet:intoString:
。返回時,您可以使用-scanUpToCharactersFromSet:
來代替,只需使用一個字符集,其中只有一個下劃線。
如果您的問題只是您的代碼的可見性,那麼您可以使用您設計的方法爲NSString
設置一個類別。那樣,你只能看到一次醜陋的混亂。 ;)
例如:
@interface NSString(Conversions) {
- (NSString *)asCamelCase;
- (NSString *)asUnderscored;
}
@implementation NSString(Conversions) {
- (NSString *)asCamelCase {
// whatever you came up with
}
- (NSString *)asUnderscored {
// whatever you came up with
}
}
編輯:一個快速谷歌搜索後,我找不到這樣做的任何方式,即使在平原。然而,我沒有找到一個框架,可能是有用的。它被稱爲RegexKitLite。它使用內置的ICU庫,因此它只爲最終的二進制文件增加了大約20K。
克里斯,感謝多的RegexKitLite指針。我一定會在未來的項目中使用它! – 2009-12-17 13:11:20
它比在iOS開發條款中發佈這個答案遲了約10萬年;應該有其他人在這裏絆倒:不要使用RegexKitLite。在發佈這個答案約六個月後,iOS 4中出現了「NSRegularExpression」,將相同的ICU庫引入標準框架。 – Tommy 2015-11-10 21:03:03
這些怎麼樣:
NSString *MyCamelCaseToUnderscores(NSString *input) {
NSMutableString *output = [NSMutableString string];
NSCharacterSet *uppercase = [NSCharacterSet uppercaseLetterCharacterSet];
for (NSInteger idx = 0; idx < [input length]; idx += 1) {
unichar c = [input characterAtIndex:idx];
if ([uppercase characterIsMember:c]) {
[output appendFormat:@"_%@", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
} else {
[output appendFormat:@"%C", c];
}
}
return output;
}
NSString *MyUnderscoresToCamelCase(NSString *underscores) {
NSMutableString *output = [NSMutableString string];
BOOL makeNextCharacterUpperCase = NO;
for (NSInteger idx = 0; idx < [underscores length]; idx += 1) {
unichar c = [underscores characterAtIndex:idx];
if (c == '_') {
makeNextCharacterUpperCase = YES;
} else if (makeNextCharacterUpperCase) {
[output appendString:[[NSString stringWithCharacters:&c length:1] uppercaseString]];
makeNextCharacterUpperCase = NO;
} else {
[output appendFormat:@"%C", c];
}
}
return output;
}
有些缺點是他們使用臨時字符串大小寫之間轉換,而他們沒有縮寫詞的任何邏輯,所以myURL將導致my_u_r_l。
這是我實現羅布的回答:
@implementation NSString (CamelCaseConversion)
// Convert a camel case string into a dased word sparated string.
// In case of scanning error, return nil.
// Camel case string must not start with a capital.
- (NSString *)fromCamelCaseToDashed {
NSScanner *scanner = [NSScanner scannerWithString:self];
scanner.caseSensitive = YES;
NSString *builder = [NSString string];
NSString *buffer = nil;
NSUInteger lastScanLocation = 0;
while ([scanner isAtEnd] == NO) {
if ([scanner scanCharactersFromSet:[NSCharacterSet lowercaseLetterCharacterSet] intoString:&buffer]) {
builder = [builder stringByAppendingString:buffer];
if ([scanner scanCharactersFromSet:[NSCharacterSet uppercaseLetterCharacterSet] intoString:&buffer]) {
builder = [builder stringByAppendingString:@"-"];
builder = [builder stringByAppendingString:[buffer lowercaseString]];
}
}
// If the scanner location has not moved, there's a problem somewhere.
if (lastScanLocation == scanner.scanLocation) return nil;
lastScanLocation = scanner.scanLocation;
}
return builder;
}
@end
爲什麼不使用NSMutableString作爲構建器? – 2013-08-05 21:21:19
確實會更好。 :-) – MonsieurDart 2013-08-21 09:09:21
我已經聯合在這裏找到了我的重構庫,es_ios_utils答案。見NSCategories.h:
@property(nonatomic, readonly) NSString *asCamelCaseFromUnderscores;
@property(nonatomic, readonly) NSString *asUnderscoresFromCamelCase;
用法:
@"my_string".asCamelCaseFromUnderscores
產量@ 「的myString」
請把改進!
這是基於上述所有情況的又一個版本。該版本處理其他表單。特別是,測試了以下內容:
camelCase => camel_case
camelCaseWord => camel_case_word
camelURL => camel_url
camelURLCase => camel_url_case
CamelCase => camel_case
這裏去
- (NSString *)fromCamelCaseToDashed3 {
NSMutableString *output = [NSMutableString string];
NSCharacterSet *uppercase = [NSCharacterSet uppercaseLetterCharacterSet];
BOOL previousCharacterWasUppercase = FALSE;
BOOL currentCharacterIsUppercase = FALSE;
unichar currentChar = 0;
unichar previousChar = 0;
for (NSInteger idx = 0; idx < [self length]; idx += 1) {
previousChar = currentChar;
currentChar = [self characterAtIndex:idx];
previousCharacterWasUppercase = currentCharacterIsUppercase;
currentCharacterIsUppercase = [uppercase characterIsMember:currentChar];
if (!previousCharacterWasUppercase && currentCharacterIsUppercase && idx > 0) {
// insert an _ between the characters
[output appendString:@"_"];
} else if (previousCharacterWasUppercase && !currentCharacterIsUppercase) {
// insert an _ before the previous character
// insert an _ before the last character in the string
if ([output length] > 1) {
unichar charTwoBack = [output characterAtIndex:[output length]-2];
if (charTwoBack != '_') {
[output insertString:@"_" atIndex:[output length]-1];
}
}
}
// Append the current character lowercase
[output appendString:[[NSString stringWithCharacters:¤tChar length:1] lowercaseString]];
}
return output;
}
'previousChar'永遠不會被讀取並且可以被刪除。 – 2014-07-01 08:32:09
我偶然發現了這個問題尋找一種方式,以駝峯式轉換爲間隔,用戶可顯示的字符串。這裏是我的解決方案,它的工作比@代替@ 「_」」「
- (NSString *)fromCamelCaseToSpaced:(NSString*)input {
NSCharacterSet* lower = [NSCharacterSet lowercaseLetterCharacterSet];
NSCharacterSet* upper = [NSCharacterSet uppercaseLetterCharacterSet];
for (int i = 1; i < input.length; i++) {
if ([upper characterIsMember:[input characterAtIndex:i]] &&
[lower characterIsMember:[input characterAtIndex:i-1]])
{
NSString* soFar = [input substringToIndex:i];
NSString* left = [input substringFromIndex:i];
return [NSString stringWithFormat:@"%@ %@", soFar, [self fromCamelCaseToSpaced:left]];
}
}
return input;
}
看起來已經很不錯了,但是:1.如果輸入爲空,該怎麼辦? 2.如何轉換回來工作? 3.你的循環不能以'i = 1'開始,使'i> 1'過時? – Trinimon 2013-03-02 10:44:36
1.如果輸入爲零,則返回零,因爲發送給零的長度消息將返回0 2.好的一點,我不需要這個在我的應用程序 3.我喜歡這一點,編輯它到我的答案 – 2013-03-02 11:55:27
試試這個神奇的更好:
NSString* camelCaseString = @"myBundleVersion";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(?<=[a-z])([A-Z])|([A-Z])(?=[a-z])" options:0 error:nil];
NSString *underscoreString = [[regex stringByReplacingMatchesInString:camelCaseString options:0 range:NSMakeRange(0, camelCaseString.length) withTemplate:@"_$1$2"] lowercaseString];
NSLog(@"%@", underscoreString);
輸出:my_bundle_version
如果該字符串是帕斯卡情況下,即MyBundleVersion,它會產生_my_bundle_version – 2014-08-11 06:34:13
我很想看到一個固定的前導下劃線和一個轉換另一種方式的版本。 – 2015-08-11 17:41:28
@PeterDeWeese,像[這一個](https://regex101.com/r/zM4dD2/1)? – 2016-02-05 13:21:01
OK傢伙。下面是一個所有正則表達式的答案,這是我考慮的唯一正確的方法:
考慮:
NSString *MYSTRING = "foo_bar";
NSRegularExpression *_toCamelCase = [NSRegularExpression
regularExpressionWithPattern:@"(_)([a-z])"
options:NSRegularExpressionCaseInsensitive error:&error];
NSString *camelCaseAttribute = [_toCamelCase
stringByReplacingMatchesInString:MYSTRING options:0
range:NSMakeRange(0, attribute.length)
withTemplate:@"\\U$2"];
息率Foobar的。
相反:
NSString *MYSTRING = "fooBar";
NSRegularExpression *camelCaseTo_ = [NSRegularExpression
regularExpressionWithPattern:@"([A-Z])"
options:0 error:&error];
NSString *underscoreParsedAttribute = [camelCaseTo_
stringByReplacingMatchesInString:MYSTRING
options:0 range:NSMakeRange(0, attribute.length)
withTemplate:@"_$1"];
underscoreParsedAttribute = [underscoreParsedAttribute lowercaseString];
產量:foo_bar這樣。
\ U $ 2替換第二捕獲組大寫版本的本身:d
\ 1然而大號$,奇怪的是,不與自身的小寫版本替換第一捕獲組:(不確定爲什麼,它應該工作:/
如果你關心你的代碼的速度,你可能要編寫的代碼更高性能的版本:
- (nonnull NSString *)camelCaseToSnakeCaseString {
if ([self length] == 0) {
return @"";
}
NSMutableString *output = [NSMutableString string];
NSCharacterSet *digitSet = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *uppercaseSet = [NSCharacterSet uppercaseLetterCharacterSet];
NSCharacterSet *lowercaseSet = [NSCharacterSet lowercaseLetterCharacterSet];
for (NSInteger idx = 0; idx < [self length]; idx += 1) {
unichar c = [self characterAtIndex:idx];
// if it's the last one then just append lowercase of character
if (idx == [self length] - 1) {
if ([uppercaseSet characterIsMember:c]) {
[output appendFormat:@"%@", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
[output appendFormat:@"%C", c];
}
continue;
}
unichar nextC = [self characterAtIndex:(idx+1)];
// this logic finds the boundaries between lowercase/uppercase/digits and lets the string be split accordingly.
if ([lowercaseSet characterIsMember:c] && [uppercaseSet characterIsMember:nextC]) {
[output appendFormat:@"%@_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else if ([lowercaseSet characterIsMember:c] && [digitSet characterIsMember:nextC]) {
[output appendFormat:@"%@_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else if ([digitSet characterIsMember:c] && [uppercaseSet characterIsMember:nextC]) {
[output appendFormat:@"%@_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
// Append lowercase of character
if ([uppercaseSet characterIsMember:c]) {
[output appendFormat:@"%@", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
[output appendFormat:@"%C", c];
}
}
}
return output;
}
感謝羅布 - 我缺乏使用NSScanner的經驗,這讓我忽略了這個解決方案,但它比我擁有的要乾淨得多。 – 2009-12-17 13:10:49