我写了一个应该很快的解决方案。这是一个 Objective-C 函数,主要使用普通的旧 C。为什么是 C?因为我们确切地知道 C 运行时的作用,它基本上提供了一个超薄的内存包装器。另一方面,Swift 运行时的许多低级细节是未知的,并且有充分的理由。但是,可以安全地假设 Swift 具有比普通 C 更高的性能开销。在这方面击败 C 的唯一方法是一直使用汇编程序或打开您选择的十六进制编辑器并输入操作码和操作数自己。不要误解我的意思,出于很多原因,应该始终首选 Swift,但如果性能至关重要,那么 Objective-C / C 是首选工具。
所以这里出现了代码 sn-p。它需要一个 NSString 并去掉所有数字并将所有大写字符转换为对应的小写字符。
- ( NSString* ) convert:( NSString* ) source
{
const char bitmaskNonAsciiChar = ( char ) ( 1 << 7 );
const char* cSource = [ source UTF8String ];
size_t strLength = strlen( cSource );
size_t bufferSize = sizeof( char ) * strLength + 1;
char *result = ( char* ) malloc( bufferSize );
memset( result, '\0', bufferSize );
int currentIndex = 0;
for( int i = 0; i < strLength; ++i )
{
// Check if this is an UTF-8 character that's longer than one byte. If so, it can't be an ASCII character and we can just write this character to the result buffer.
if( ( cSource[ i ] & bitmaskNonAsciiChar ) == bitmaskNonAsciiChar )
{
result[ currentIndex++ ] = cSource[ i ];
continue;
}
// Now we know it is an ASCII character, so we need to check for digits and upper-case characters.
if( cSource[ i ] >= ( char ) 46 && cSource[ i ] <= ( char ) 57 )
{
continue;
}
if( cSource[ i ] >= ( char ) 65 && cSource[ i ] <= ( char ) 90 )
{
result[ currentIndex++ ] = cSource[ i ] + ( char ) 32;
continue;
}
// It's an ASCII character that is neither a digit nor upper-cased, so we just write it to the result buffer.
result[ currentIndex++ ] = cSource[ i ];
}
NSString *resultString = [ NSString stringWithUTF8String: result ];
free( result );
return resultString;
}
这是一个稍微修改过的版本,如果您确定输入大小相当小,可以使用它。此版本不使用 malloc 在堆上创建结果缓冲区,而是简单地使用堆栈内存。如果您想逐字逐句地运行它,那么为每次调用分配所有这些内存是浪费大量时间。但是,如果您打算逐个文件地运行它并且您不知道文件可能会变得多大,那么第一个版本可能会更好。
- ( NSString* ) convert:( NSString* ) source
{
const char bitmaskNonAsciiChar = ( char ) ( 1 << 7 );
const char* cSource = [ source UTF8String ];
size_t strLength = strlen( cSource );
size_t bufferSize = sizeof( char ) * strLength + 1;
char result[ bufferSize ];
memset( result, '\0', bufferSize );
int currentIndex = 0;
for( int i = 0; i < strLength; ++i )
{
// Check if this is an UTF-8 character that's longer than one byte. If so, it can't be an ASCII character and we can just write this character to the result buffer.
if( ( cSource[ i ] & bitmaskNonAsciiChar ) == bitmaskNonAsciiChar )
{
result[ currentIndex++ ] = cSource[ i ];
continue;
}
// Now we know it is an ASCII character, so we need to check for digits and upper-case characters.
if( cSource[ i ] >= ( char ) 46 && cSource[ i ] <= ( char ) 57 )
{
continue;
}
if( cSource[ i ] >= ( char ) 65 && cSource[ i ] <= ( char ) 90 )
{
result[ currentIndex++ ] = cSource[ i ] + ( char ) 32;
continue;
}
// It's an ASCII character that is neither a digit nor upper-cased, so we just write it to the result buffer.
result[ currentIndex++ ] = cSource[ i ];
}
NSString *resultString = [ NSString stringWithUTF8String: result ];
return resultString;
}