在Clojure/Java中检测Unicode文本连字

Abh*_*kar 6 java unicode text clojure ligature

连字是Unicode字符,由多个代码点表示.例如,在Devanagari中???是一个由代码点组成的连字? + ? + ?.

在简单的文本文件编辑器中看到,如记事本,???显示为?? + ?并存储为三个Unicode字符.但是,当在Firefox中打开相同的文件时,它会显示为正确的连字.

所以我的问题是,如何从我的代码中读取文件时以编程方式检测此类连字.自从Firefox成功以来,必须有一种以编程方式完成它的方法.是否有任何包含此信息的Unicode属性,或者我是否需要有所有此类连字的映射?

text-rendering设置为SVG CSS属性时optimizeLegibility做同样的事情(将代码点组合成适当的连字).

PS:我正在使用Java.

编辑

我的代码的目的是计算Unicode文本中的字符,假设连字是一个单一字符.所以我需要一种方法将多个代码点折叠成一个连字.

Abh*_*kar 1

虽然亚伦的答案并不完全正确,但它把我推向了正确的方向。在阅读了 Java API 文档java.awt.font.GlyphVector并在 Clojure REPL 上玩了很多之后,我能够编写一个可以完成我想要的功能的函数。

这个想法是找到 中字形的宽度,glyphVector并将零宽度的字形与最后找到的非零宽度字形组合起来。解决方案是在 Clojure 中,但如果需要,它应该可以转换为 Java。

(ns net.abhinavsarkar.unicode
  (:import [java.awt.font TextAttribute GlyphVector]
           [java.awt Font]
           [javax.swing JTextArea]))

(let [^java.util.Map text-attrs {
        TextAttribute/FAMILY "Arial Unicode MS"
        TextAttribute/SIZE 25
        TextAttribute/LIGATURES TextAttribute/LIGATURES_ON}
      font (Font/getFont text-attrs)
      ta (doto (JTextArea.) (.setFont font))
      frc (.getFontRenderContext (.getFontMetrics ta font))]
  (defn unicode-partition
    "takes an unicode string and returns a vector of strings by partitioning
    the input string in such a way that multiple code points of a single
    ligature are in same partition in the output vector"
    [^String text]
    (let [glyph-vector 
            (.layoutGlyphVector
              font, frc, (.toCharArray text),
              0, (.length text), Font/LAYOUT_LEFT_TO_RIGHT)
          glyph-num (.getNumGlyphs glyph-vector)
          glyph-positions
            (map first (partition 2
                          (.getGlyphPositions glyph-vector 0 glyph-num nil)))
          glyph-widths
            (map -
              (concat (next glyph-positions)
                      [(.. glyph-vector getLogicalBounds width)])
              glyph-positions)
          glyph-indices 
            (seq (.getGlyphCharIndices glyph-vector 0 glyph-num nil))
          glyph-index-width-map (zipmap glyph-indices glyph-widths)
          corrected-glyph-widths
            (vec (reduce
                    (fn [acc [k v]] (do (aset acc k v) acc))
                    (make-array Float (count glyph-index-width-map))
                    glyph-index-width-map))]
      (loop [idx 0 pidx 0 char-seq text acc []]
        (if (nil? char-seq)
          acc
          (if-not (zero? (nth corrected-glyph-widths idx))
            (recur (inc idx) (inc pidx) (next char-seq)
              (conj acc (str (first char-seq))))
            (recur (inc idx) pidx (next char-seq)
              (assoc acc (dec pidx)
                (str (nth acc (dec pidx)) (first char-seq))))))))))
Run Code Online (Sandbox Code Playgroud)

也发布在 Gist 上