为什么我的 NSMutableString 编辑有时不起作用?
Why does my NSMutableString edit sometimes not work?
我正在尝试修复一些编号错误的电影字幕文件(每个子文件由一个空行分隔)。以下代码扫描测试文件中的错误字幕索引号。如果我只是 'printf' 错误的 old 索引和替换 new 索引,一切都会按预期显示。
//######################################################################
-(IBAction)scanToSubIndex:(id)sender
{
NSMutableString* tempString = [[NSMutableString alloc] initWithString:[theTextView string]];
int textLen = (int)[tempString length];
NSScanner *theScanner = [NSScanner scannerWithString:tempString];
while ([theScanner isAtEnd] == NO)
{
[theScanner scanUpToString:@"\r\n\r\n" intoString:NULL];
[theScanner scanString:@"\r\n\r\n" intoString:NULL];
if([theScanner scanLocation] >= textLen)
break;
else
{ // remove OLD subtitle index...
NSString *oldNumStr;
[theScanner scanUpToString:@"\r\n" intoString:&oldNumStr];
printf("old number:%s\n", [oldNumStr UTF8String]);
NSRange range = [tempString rangeOfString:oldNumStr];
[tempString deleteCharactersInRange:range];
// ...and insert SEQUENTIAL index
NSString *newNumStr = [self changeSubIndex];
printf("new number:%s\n\n", [newNumStr UTF8String]);
[tempString insertString:newNumStr atIndex:range.location];
}
}
printf("\ntempString\n\n:%s\n", [tempString UTF8String]);
}
//######################################################################
-(NSString*)changeSubIndex
{
static int newIndex = 1;
// convert int to string and return...
NSString *numString = [NSString stringWithFormat:@"%d", newIndex];
++newIndex;
return numString;
}
然而,当我尝试将新索引写入静音字符串时,我最终得到了这样的无序结果:
sub 1
sub 2
sub 3
sub 1
sub 5
sub 6
sub 7
sub 5
sub 9
sub 7
sub 8
一个有趣的观察(和可能的线索?)是,当我到达 字幕编号 1000 时,每个数字都按要求按顺序写入可变字符串。我已经为此苦苦挣扎了几个星期,而且我在 SO 上找不到任何其他类似的问题。非常感谢任何帮助:-)
NSScanner & NSMutableString
NSMutableString
是 NSString
的子 class。换句话说,您可以在需要 NSString
的地方传递 NSMutableString
。但这并不意味着您可以修改它。
scannerWithString:
预计 NSString
。翻译成人类语言——我期待一个字符串,我也期待这个字符串是 read-only(不会被修改)。
换句话说 - 你的代码被认为是程序员错误 - 你给 NSScanner
一些东西,NSScanner
期望不可变的字符串并且你正在修改它。
我们不知道 NSScanner
class 在幕后做了什么。可以有缓冲或任何其他类型的优化。
即使您幸运地使用了提到的 scanLocation
修复(在评论中),您也不应该依赖它,因为 底层实现 可以随任何新版本更改。
不要这样做。不仅在这里,而且在任何你看到不可变数据类型的地方。
(在某些情况下您可以这样做,但是您应该真正了解 幕后实现 正在做什么,确保它不会被修改,等等.但一般来说,除非你知道自己在做什么,否则这不是一个好主意。)
样本
此示例代码基于以下假设:
- 我们正在谈论 SubRip 文本 (SRT)
- 文件很小(可以轻松放入内存)
- SRT 文件的其余部分是正确的
- 尤其是分隔符 (
@"\r\n"
)
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
@interface SubRipText : NSObject
+ (NSString *)fixSubtitleIndexes:(NSString *)string;
@end
NS_ASSUME_NONNULL_END
@implementation SubRipText
+ (NSString *)fixSubtitleIndexes:(NSString *)string {
NSMutableString *result = [@"" mutableCopy];
__block BOOL nextLineIsIndex = YES;
__block NSUInteger index = 1;
[string enumerateLinesUsingBlock:^(NSString * _Nonnull line, BOOL * _Nonnull stop) {
if (nextLineIsIndex) {
[result appendFormat:@"%lu\r\n", (unsigned long)index];
index++;
nextLineIsIndex = NO;
return;
}
[result appendFormat:@"%@\r\n", line];
nextLineIsIndex = line.length == 0;
}];
return result;
}
@end
用法:
NSString *test = @"29\r\n"
"00:00:00,498 --> 00:00:02,827\r\n"
"Hallo\r\n"
"\r\n"
"4023\r\n"
"00:00:02,827 --> 00:00:06,383\r\n"
"This is two lines,\r\n"
"subtitles rocks!\r\n"
"\r\n"
"1234\r\n"
"00:00:06,383 --> 00:00:09,427\r\n"
"Maybe not,\r\n"
"just learn English :)\r\n";
NSString *result = [SubRipText fixSubtitleIndexes:test];
NSLog(@"%@", result);
输出:
1
00:00:00,498 --> 00:00:02,827
Hallo
2
00:00:02,827 --> 00:00:06,383
This is two lines,
subtitles rocks!
3
00:00:06,383 --> 00:00:09,427
Maybe not,
just learn English :)
还有其他方法可以实现此目的,但您应该考虑可读性、写入速度、运行 的速度,...取决于您的使用情况 - 您要使用多少种方法修复等
我正在尝试修复一些编号错误的电影字幕文件(每个子文件由一个空行分隔)。以下代码扫描测试文件中的错误字幕索引号。如果我只是 'printf' 错误的 old 索引和替换 new 索引,一切都会按预期显示。
//######################################################################
-(IBAction)scanToSubIndex:(id)sender
{
NSMutableString* tempString = [[NSMutableString alloc] initWithString:[theTextView string]];
int textLen = (int)[tempString length];
NSScanner *theScanner = [NSScanner scannerWithString:tempString];
while ([theScanner isAtEnd] == NO)
{
[theScanner scanUpToString:@"\r\n\r\n" intoString:NULL];
[theScanner scanString:@"\r\n\r\n" intoString:NULL];
if([theScanner scanLocation] >= textLen)
break;
else
{ // remove OLD subtitle index...
NSString *oldNumStr;
[theScanner scanUpToString:@"\r\n" intoString:&oldNumStr];
printf("old number:%s\n", [oldNumStr UTF8String]);
NSRange range = [tempString rangeOfString:oldNumStr];
[tempString deleteCharactersInRange:range];
// ...and insert SEQUENTIAL index
NSString *newNumStr = [self changeSubIndex];
printf("new number:%s\n\n", [newNumStr UTF8String]);
[tempString insertString:newNumStr atIndex:range.location];
}
}
printf("\ntempString\n\n:%s\n", [tempString UTF8String]);
}
//######################################################################
-(NSString*)changeSubIndex
{
static int newIndex = 1;
// convert int to string and return...
NSString *numString = [NSString stringWithFormat:@"%d", newIndex];
++newIndex;
return numString;
}
然而,当我尝试将新索引写入静音字符串时,我最终得到了这样的无序结果:
sub 1
sub 2
sub 3
sub 1
sub 5
sub 6
sub 7
sub 5
sub 9
sub 7
sub 8
一个有趣的观察(和可能的线索?)是,当我到达 字幕编号 1000 时,每个数字都按要求按顺序写入可变字符串。我已经为此苦苦挣扎了几个星期,而且我在 SO 上找不到任何其他类似的问题。非常感谢任何帮助:-)
NSScanner & NSMutableString
NSMutableString
是 NSString
的子 class。换句话说,您可以在需要 NSString
的地方传递 NSMutableString
。但这并不意味着您可以修改它。
scannerWithString:
预计 NSString
。翻译成人类语言——我期待一个字符串,我也期待这个字符串是 read-only(不会被修改)。
换句话说 - 你的代码被认为是程序员错误 - 你给 NSScanner
一些东西,NSScanner
期望不可变的字符串并且你正在修改它。
我们不知道 NSScanner
class 在幕后做了什么。可以有缓冲或任何其他类型的优化。
即使您幸运地使用了提到的 scanLocation
修复(在评论中),您也不应该依赖它,因为 底层实现 可以随任何新版本更改。
不要这样做。不仅在这里,而且在任何你看到不可变数据类型的地方。
(在某些情况下您可以这样做,但是您应该真正了解 幕后实现 正在做什么,确保它不会被修改,等等.但一般来说,除非你知道自己在做什么,否则这不是一个好主意。)
样本
此示例代码基于以下假设:
- 我们正在谈论 SubRip 文本 (SRT)
- 文件很小(可以轻松放入内存)
- SRT 文件的其余部分是正确的
- 尤其是分隔符 (
@"\r\n"
)
- 尤其是分隔符 (
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
@interface SubRipText : NSObject
+ (NSString *)fixSubtitleIndexes:(NSString *)string;
@end
NS_ASSUME_NONNULL_END
@implementation SubRipText
+ (NSString *)fixSubtitleIndexes:(NSString *)string {
NSMutableString *result = [@"" mutableCopy];
__block BOOL nextLineIsIndex = YES;
__block NSUInteger index = 1;
[string enumerateLinesUsingBlock:^(NSString * _Nonnull line, BOOL * _Nonnull stop) {
if (nextLineIsIndex) {
[result appendFormat:@"%lu\r\n", (unsigned long)index];
index++;
nextLineIsIndex = NO;
return;
}
[result appendFormat:@"%@\r\n", line];
nextLineIsIndex = line.length == 0;
}];
return result;
}
@end
用法:
NSString *test = @"29\r\n"
"00:00:00,498 --> 00:00:02,827\r\n"
"Hallo\r\n"
"\r\n"
"4023\r\n"
"00:00:02,827 --> 00:00:06,383\r\n"
"This is two lines,\r\n"
"subtitles rocks!\r\n"
"\r\n"
"1234\r\n"
"00:00:06,383 --> 00:00:09,427\r\n"
"Maybe not,\r\n"
"just learn English :)\r\n";
NSString *result = [SubRipText fixSubtitleIndexes:test];
NSLog(@"%@", result);
输出:
1
00:00:00,498 --> 00:00:02,827
Hallo
2
00:00:02,827 --> 00:00:06,383
This is two lines,
subtitles rocks!
3
00:00:06,383 --> 00:00:09,427
Maybe not,
just learn English :)
还有其他方法可以实现此目的,但您应该考虑可读性、写入速度、运行 的速度,...取决于您的使用情况 - 您要使用多少种方法修复等