我在寻找一种简单,有效的方式转换为字符串首字母大写强调符号(即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