Pergunta

Ligaduras são caracteres Unicode representados por mais de um ponto de código.Por exemplo, em Devanágari त्र é uma ligadura que consiste em pontos de código त + ् + र.

Quando visto em editores de arquivos de texto simples como o Bloco de Notas, त्र é mostrado como त् + र e é armazenado como três caracteres Unicode.Porém quando o mesmo arquivo é aberto no Firefox, ele é mostrado como uma ligadura adequada.

Então, minha pergunta é: como detectar essas ligaduras programaticamente ao ler o arquivo do meu código.Como o Firefox faz isso, deve existir uma maneira de fazer isso programaticamente.Existe alguma propriedade Unicode que contenha essas informações ou preciso ter um mapa para todas essas ligaduras?

Propriedade CSS SVG text-rendering quando definido para optimizeLegibility faz a mesma coisa (combina pontos de código na ligadura adequada).

PS:Estou usando Java.

EDITAR

O objetivo do meu código é contar os caracteres no texto Unicode, assumindo que uma ligadura é um único caractere.Portanto, preciso de uma maneira de recolher vários pontos de código em uma única ligadura.

Foi útil?

Solução 4

Enquanto Resposta de Aaron não está exatamente correto, ele me empurrou na direção certa. Depois de ler a API Java Docs of java.awt.font.GlyphVector E jogando muito no Clojure Repl, pude escrever uma função que faz o que eu quero.

A idéia é encontrar a largura dos glifos no glyphVector e combine os glifos com a largura zero com o último glifo de largura diferente de zero. A solução está em clojure, mas deve ser traduzível para Java, se necessário.

(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))))))))))

Também postado na GIST.

Outras dicas

o Tipóstia de computador Página da Wikipedia diz -

O tipo de letra romano moderno do computador fornecido com Tex inclui as cinco ligantes comuns FF, FI, FL, FFI e FFL. Quando a TEX encontra essas combinações em um texto, ele substitui a ligadura apropriada, a menos que seja substituído pelo tipador.

Isso indica que é o editor que substitui. Além disso,

A Unicode sustenta que a ligadura é uma questão de apresentação e não uma questão de definição de personagem, e que, por exemplo, "se uma fonte moderna é solicitada a exibir 'H' seguida por 'r', e a fonte tem uma ligadura 'HR' , ele pode exibir a ligadura. "

Até onde eu vejo (tenho algum interesse nesse tópico e agora lendo poucos artigos), as instruções para o substituto da ligadura são incorporadas dentro da fonte. Agora, eu cavei mais e os encontrei para você; GSUB - A tabela de substituição de glifos e Subtable de substituição de ligadura A partir da especificação do formato de arquivo OpenType.

Em seguida, você precisa encontrar alguma biblioteca que possa permitir que você atinja os arquivos de fonte OpenType, ou seja, o analisador de arquivos para acesso rápido. Lendo os dois seguintes discussões Pode lhe dar algumas instruções sobre como fazer essas substituições:

  1. Bug de cromo http://code.google.com/p/chromium/issues/detail?id=22240
  2. Bug Firefox https://bugs.launchpad.net/firefox/+bug/37828

O que você está falando não são ligaduras (pelo menos não na linguagem unicode), mas em aglomerados. Existe um anexo padrão que se preocupa em descobrir os limites do texto, incluindo limites de cluster de grafema:

http://www.unicode.org/reports/tr29/tr29-15.html#grapheme_cluster_bounders

Veja também a descrição dos clusters de grafema personalizados em expressões regulares:

http://unicode.org/reports/tr18/#tailored_graphemes_clusters

E a definição de grafemas de agrupamento:

http://www.unicode.org/reports/tr10/#collation_graphemes

Eu acho que esses são pontos de partida. A parte mais difícil provavelmente será encontrar uma implementação Java do algoritmo de agrupamento Unicode que funcione para os locais de Devanagari. Se você encontrar um, poderá analisar strings sem recorrer aos recursos do OpenType. Isso seria um pouco mais limpo, já que o OpenType se preocupa com detalhes puramente da apresentação e não com a semântica de caráter ou agrupamento de cluster, mas o algoritmo de agrupamento e o algoritmo de descoberta de limite de cluster de grafema personalizado parecem ser implementados independentemente das fontes.

Você pode obter essas informações na classe GlyphVector.

Para uma determinada String, uma instância de Font pode criar um GlyphVector que pode fornecer informações sobre a renderização do texto.

O layoutGlifoVetor() método na fonte pode fornecer isso.

O FLAG_COMPLEX_GLYPHS O atributo do GlyphVector pode informar se o texto não possui um mapeamento de 1 para 1 com os caracteres de entrada.

O código a seguir mostra um exemplo disso:

JTextField textField = new JTextField();
String textToTest = "abcdefg";
FontRenderContext fontRenderContext = textField.getFontMetrics(font).getFontRenderContext();

GlyphVector glyphVector = font.layoutGlyphVector(fontRenderContext, textToTest.toCharArray(), 0, 4, Font.LAYOUT_LEFT_TO_RIGHT);
int layoutFlags = glyphVector.getLayoutFlags();
boolean hasComplexGlyphs = (layoutFlags & GlyphVector.FLAG_COMPLEX_GLYPHS) != 0;
int numberOfGlyphs = glyphVector.getNumGlyphs();

numberOfGlyphs deve representar o número de caracteres usados ​​para exibir o texto de entrada.

Infelizmente você precisa criar um componente Java GUI para obter o FontRenderContext.

Eu acho que o que você realmente está procurando é Unicode Normalization.

Para Java, você deve verificar http://download.oracle.com/javase/6/docs/api/java/text/normalizer.html

Ao escolher o formulário de normalização adequado, você pode obter o que está procurando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top