【问题标题】:What is the best way to get a string that fits the provided width in pixels?获取适合提供的像素宽度的字符串的最佳方法是什么?
【发布时间】:2009-07-22 06:57:57
【问题描述】:

我现在遇到了一个问题,即获取一个符合提供的像素宽度的字符串。

例如,如果我有这样的句子(在 JavaScript 中):

var mystring = "This is my sentence, I need to get just 50 pixels from it."

如果我在 C# 中使用 MeasureString 方法,我可以获得宽度:

Font font = new Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Point);
SizeF size = graphics.MeasureString(mystring, font);

假设这个字符串的宽度是 400 像素,但我可以在网站上显示的最大宽度是 50 像素。

如果我缩短字符串并对其进行测量,直到其宽度小于 50 像素,它可以工作,但它需要多次迭代,这根本不是一个好的解决方案

有人对此有好的解决方案吗?

谢谢。

【问题讨论】:

  • JavaScript 是从哪里来的?
  • 所有框架中大部分DrawText函数都具有矩形限制文本的能力,为什么不提供边界让系统处理呢?
  • JavaScript 从何而来?因为我可以从 Ajax 调用中获取数据,所以如果有好的解决方案,也可以通过 javascript 进行剪切。
  • @Shay Erlichmen :我会检查是否有这样的解决方案。
  • 你控制网页标记吗?您是否担心文本被截断的位置?如果答案分别是“是”和“否”,那么您可以将相关显示元素的内容剪裁为 50px 并保留文本。

标签: c# javascript measurement


【解决方案1】:

使用二分法搜索最佳长度应该不需要多次迭代。鉴于文本渲染的复杂性,我相信这是你能做的最好的。您不能只为每个字符取一个宽度并将它们加在一起。

【讨论】:

    【解决方案2】:

    我想在这个部分添加 - “如果我缩短字符串并测量它直到它小于 50px 宽度......”

    为什么不从字符串的中间开始进行二分查找。这是初学者的location。无论字符串有多长 - 找出理想长度所需的时间要少得多。复杂度从 n 降低到 log(n)。

    为了获得更好的结果,如果字符串真的很长,例如 500 个字符,您可以在开始二进制搜索之前截断它。

    【讨论】:

      【解决方案3】:
      string myString = "This is my sentence, I need to get just 50 pixels from it."
      Font font = new Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Point); 
      
      int desiredWidth = 50;
      int myStringWidth = TextRenderer.MeasureText(myString , font).Width;
      string result = mystring.Substring(0, myString.Length * desiredWidth / myStringWidth);
      

      此解决方案不考虑换行符。

      【讨论】:

        【解决方案4】:

        您可以将字符串的宽度近似为子字符串的宽度之和。如果您的子字符串以空格为界†,它甚至可能是一个非常好的近似值。但是,除非您询问确切任何特定字符串的宽度,否则您无法知道,因为文本渲染引擎会执行诸如字距调整(改变字符之间的间距)之类的事情。

        † 并且您可能希望它们至少在欧洲语言中是这样,因为阅读仅在空白处断开的文本比在中间词中断开的文本要容易得多,即使它导致文本看起来稍微有些粗糙。

        【讨论】:

          【解决方案5】:

          StringBoxer 类的 GetBoxedString 方法“估计”可以放入矩形并返回的字符串数量(空格分隔的单词、Enter 分隔的单词甚至长字符)(复制/粘贴时要小心,因为我无法将整个代码放入下面的灰色框中):

          公共密封类 StringBoxer {

          public string GetBoxedString(string s, Size size, Font font)
          {
          
            int longestStringLengthInWidth = 0;
            var result = string.Empty;
            if (size.Height < font.Height)
            {
              return string.Empty;
            }
          
            using (var bmp = new Bitmap(size.Width, size.Height))
            {
              int index = 0;
              var words = this.SplitString(s);
          
          
              var measuredSizeBeforeAddingWord = new SizeF(0, 0);
          
              using (var graphic = Graphics.FromImage(bmp))
              {
                longestStringLengthInWidth = CalculateLongestStringLength(size, font);
          
                do
                {
                  if (words[index].Length > longestStringLengthInWidth)
                  {
                    //// If a word is longer than the maximum string length for the specified size then break it into characters and add char 0 at the begining of each of those characters
                    var brokenCharacters = words[index].Select(c => ((char)0) + c.ToString()).ToList();
                    brokenCharacters.Add(" ");
                    words.RemoveAt(index);
                    words.InsertRange(index, brokenCharacters);
                  }
          
                  var measuredSizeAfterAddingWord = graphic.MeasureString(result + (!words[index].EndsWith("\n") ? words[index] + " " : words[index]), font, size);
                  if ((words[index].Contains('\n') || measuredSizeAfterAddingWord == measuredSizeBeforeAddingWord) && measuredSizeAfterAddingWord.Height >= size.Height-font.Height)
                  {
                    return result.TrimEnd();
                  }
          
                  measuredSizeBeforeAddingWord = measuredSizeAfterAddingWord;
          
                  if (words[index].Contains((char)0))
                  {
                    result += words[index].Replace(((char)0).ToString(), string.Empty);
                  }
                  else
                  {
                    result += (!words[index].EndsWith("\n") ? words[index] + " " : words[index]);
                  }
          
                  index++;
                }
                while (index < words.Count);
              }
            }
          
            return result.TrimEnd();
          }
          
          private List<string> SplitString(string s)
          {
            var words = s.Split(' ').ToList();
            var index = 0;
            do
            {
              // If a word contains Enter key(s) then break it into more words and replace them with the original word.
              if (!words[index].Contains("\n"))
              {
                index++;
                continue;
              }
          
              var enterSplitWords = (words[index] + " ").Split('\n');
              var brokenWords = enterSplitWords.Select(str => (enterSplitWords.LastOrDefault() != str ? str + "\n" : str).Replace(" ", string.Empty)).ToList();
              words.RemoveAt(index);
              words.InsertRange(index, brokenWords);
              index += brokenWords.Count;
            }
            while (index < words.Count);
          
            return words;
          }
          
          private static int CalculateLongestStringLength(Size size, Font font)
          {
            var tempString = string.Empty;
            var longestStringLengthInWidth = 0;
            using (var bmp = new Bitmap(size.Width, size.Height))
            {
              using (var graphic = Graphics.FromImage(bmp))
              {
                do
                {
                  if (Math.Floor(graphic.MeasureString(tempString, font, size).Height) <= font.Height)
                  {
                    longestStringLengthInWidth++;
                  }
                  else
                  {
                    break;
                  }
          
                  tempString += "x";
                } while (true);
              }
            }
          
            return longestStringLengthInWidth;
          }
          

          }

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-11-16
            • 2016-04-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多