NSString constrainedToSize方法?

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)

问题是,当它有足够的空间时,这有时会使字符串太短.我认为这是最后一个条件发挥作用的地方.我如何确保它不会切断太多

ben*_*ado 6

好消息!有一种"计算机科学/数学方法"可以更快地完成这项工作.

您链接示例执行线性搜索:它只是从字符串末尾一次切换一个字符,直到它足够短.因此,它所花费的时间将与字符串的长度成线性比例,而对于长字符串,它将非常慢,正如您所发现的那样.

但是,您可以轻松地将二进制搜索技术应用于字符串.你可以从中间开始,而不是从最后开始并一次放下一个角色:

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加或减一.