在Java或Scala中分解长行文本

时间:2013-11-20 21:53:57

标签: java scala word-wrap

我有一个String longLineOfWords,我希望分成几行(List<String> severalShortLinesOfWords或类似的行)。

线是否太长,因此应该分解,由以下函数决定:

private def isLineTooLong(line: String): Boolean = {
  val bufferedImage = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB)
  val graphics = bufferedImage.getGraphics

  val metrics = graphics.getFontMetrics(font)

  metrics.stringWidth(line) > imgWidth
}

这对我来说很困难。有人能帮助我吗?

2 个答案:

答案 0 :(得分:2)

isLineTooLong方法的实施不会影响您解决此问题的方法。

您需要做的是:

  1. 将该行拆分为单词。
  2. 创建一个空列表。
  3. 以空字符串s
  4. 开头
  5. 反复向s添加一个单词,直到它变得太长或用完为止
  6. 回溯一个单词 - 在添加单词之前使用上一行,并将其添加到结果列表中。把你没用过的单词推回到单词集合上!
  7. 从步骤3开始重复此过程,直到您没有更多的话
  8. 非常重要:在屏幕上显示结果列表,以检查它是否近似正确。
  9. 这称为自动换行。实际上你要做的就是用默认字体对文本进行自动换行显示(注意:这可能不是固定宽度的字体,所以如果在固定宽度字体的终端中打印出来的话会得到这样的结果可能比你想象的更加参差不齐。)

    要在Scala中实现上述算法,您可以使用递归,迭代或递归方案,例如fold和展开。使用您喜欢的任何一种。您也可以使用递归或迭代在Java中实现它。

    顺便说一句,你可以通过做我称之为“手动部分评估”和缩小图像大小来提高isLineTooLong效率,如下所示:

    private val isLineTooLong: String => Boolean = {
      val bufferedImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB)
      val graphics = bufferedImage.getGraphics
    
      val metrics = graphics.getFontMetrics(font)
    
      (line: String) => metrics.stringWidth(line) > imgWidth
    }
    

    此优化的唯一缺点是BufferedImage及其中引用的关联对象在isLineTooLong本身是垃圾收集之前不会被垃圾收集(这可能永远不会,取决于您放置的位置它)。

答案 1 :(得分:0)

我快速打了下面的一遍,这样你就可以推断逻辑了。我不会将此作为最终答案,因为它仍然留在“内部,但它应该让你开始。

这是将字符串包装到字符串列表中。每个单元格包含赋予函数的字符数。所以它是用字符长度包装而不是每行字数。

object Extra1 {
  val zs = "Perform Word Wrapping by a set line length over a list"
                                                  //> zs  : String = Perform Word Wrapping by a set line length over a list
  Format(zs, 5)                                   //> res0: List[String] = List(Perfo, rm Wo, rd Wr, appin, "g by ", a set, " line
                                                  //| ", " leng", th ov, "er a ", list)
}


object Format {
  def apply(line: String, n: Int): List[String] = {
    val chars = line.toList
    def loop(words: List[Char], acc: List[Char], facc: List[String]): List[String] = words match {
      case Nil => acc.mkString.reverse :: facc
      case x if(acc.length >= n) => loop(x, List[Char](), (acc.mkString).reverse :: facc)
      case char::xs => loop(xs, char :: acc, facc)//(xs, (char.toString ++ acc))
    }
    loop(chars, List[Char](), List[String]()).reverse
  }
}