Sno*_*man 3 algorithm cocoa objective-c core-text ios
不要与NSString sizeWithFont返回a 的方法混淆CGSize,我正在寻找的是一种将NSString约束返回到某个特定的方法CGSize.我想这样做的原因是,在绘制文本时Core Text,我可以在字符串的末尾附加一个省略号(...).我知道NSString's drawInRect方法为我做了这个,但我正在使用Core Text,并kCTLineBreakByTruncatingTail截断每行的结尾而不是字符串的结尾.
有这种方法,我发现是截断一个字符串,以一定的宽度,而且它并不难改变它,使之成为一个工作CGSize,但该方法对长字符串令人难以置信的速度慢,几乎是不可用的.(截断长字符串花了10多秒).必须有更多的"计算机科学"/数学算法才能更快地完成这项工作.谁敢大胆尝试提出更快的实施?
编辑:我已设法将其转换为二进制算法:
-(NSString*)getStringByTruncatingToSize:(CGSize)size string:(NSString*)string withFont:(UIFont*)font
{
int min = 0, max = string.length, mid;
while (min < max) {
mid = (min+max)/2;
NSString *currentString = [string substringWithRange:NSMakeRange(min, mid - min)];
CGSize currentSize = [currentString sizeWithFont:font constrainedToSize:CGSizeMake(size.width, MAXFLOAT)];
if (currentSize.height < size.height){
min = mid + 1;
} else if (currentSize.height > size.height) {
max = mid - 1;
} else {
break;
}
}
NSMutableString *finalString = [[string substringWithRange:NSMakeRange(0, min)] mutableCopy];
if(finalString.length < self.length)
[finalString replaceCharactersInRange:NSMakeRange(finalString.length - 3, 3) withString:@"..."];
return finalString;
}
Run Code Online (Sandbox Code Playgroud)
问题是,当它有足够的空间时,这有时会使字符串太短.我认为这是最后一个条件发挥作用的地方.我如何确保它不会切断太多?
好消息!有一种"计算机科学/数学方法"可以更快地完成这项工作.
您链接的示例执行线性搜索:它只是从字符串末尾一次切换一个字符,直到它足够短.因此,它所花费的时间将与字符串的长度成线性比例,而对于长字符串,它将非常慢,正如您所发现的那样.
但是,您可以轻松地将二进制搜索技术应用于字符串.你可以从中间开始,而不是从最后开始并一次放下一个角色:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
^
Run Code Online (Sandbox Code Playgroud)
你计算"这就是那个字符串"的宽度.如果太宽,则将测试点移动到左侧空间的中点.像这样:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
^ |
Run Code Online (Sandbox Code Playgroud)
另一方面,如果它不够宽,则将测试点移动到另一半的中点:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
| ^
Run Code Online (Sandbox Code Playgroud)
重复此操作,直到找到宽度限制之下的点.因为你每次将你的搜索区域分成两半,所以你永远不需要计算宽度超过log2 N倍(其中N是字符串的长度),即使对于非常长的字符串也不会非常快速地增长.
换句话说,如果你将输入字符串的长度加倍,那只是一个额外的宽度计算.
从维基百科的二进制搜索示例开始,这是一个例子.请注意,由于我们不是在寻找完全匹配(您想要最大的匹配),因此逻辑略有不同.
int binary_search(NSString *A, float max_width, int imin, int imax)
{
// continue searching while [imin,imax] is not empty
while (imax >= imin)
{
/* calculate the midpoint for roughly equal partition */
int imid = (imin + imax) / 2;
// determine which subarray to search
float width = ComputeWidthOfString([A substringToIndex:imid]);
if (width < max_width)
// change min index to search upper subarray
imin = imid + 1;
else if (width > max_width )
// change max index to search lower subarray
imax = imid - 1;
else
// exact match found at index imid
return imid;
}
// Normally, this is the "not found" case, but we're just looking for
// the best fit, so we return something here.
return imin;
}
Run Code Online (Sandbox Code Playgroud)
你需要做一些数学运算或测试来找出底部正确的索引是什么,但它肯定是,imin或者imax加或减一.
| 归档时间: |
|
| 查看次数: |
853 次 |
| 最近记录: |