在Unicode中查找字形相似的字符?

时间:2011-01-30 23:39:21

标签: unicode glyph

假设我有角色Ú,Ù,Ü。所有这些都与英语U字形相似。

是否有一些列表或算法可以执行此操作:

  • 鉴于Ú或Ù或Ü返回英语U
  • 给定英语U,返回所有U相似字符的列表

我不确定所有字体的Unicode字符的代码点是否相同? 如果是的话,我想可以有一些简单的方法和有效的方法来做到这一点?

更新

如果你正在使用Ruby,那么有一个可用的gem unicode-confusable可能在某些情况下有用。

3 个答案:

答案 0 :(得分:28)

目前还不清楚你要在这里做什么。

  • 有些规范分解的字符都以相同的基本字符开头:e,é,ê,ë,ē,ĕ,ė,ę,ě,ȅ,ȇ,ȩ ,ḕ,ḗ,ḙ,ḛ,ḝ,ẹ,ẻ,ẽ,ế,ề,ể,ễ,ệ,e̳,... s,ś,ŝ,ş,š,ş, ṡ,ṣ,ṥ,ṧ,ṩ,......

  • 有些兼容性分解都包含特定字符的字符:ᵉ,ₑ,ℯ,ⅇ,⒠,ⓔ,㋍,㋎,e,... s,s,ˢ,ẛ,₨,℁,⒮,ⓢ,㎧,㎨,㎮,㎯,㎰,㎱,㎲,㎳,㏛,ft,st,s,... R,ᴿ,₨,ℛ,ℜ,ℝ,Ⓡ,㏚,R,......。

  • 在某些字体中有恰好相似的字符:ß和β和β, 3和Ʒ和Ȝ和ȝ和ʒ和ӡ和ᴣ,ɣ和ɤ和γ, F和Ϝ和ϝ, B和Β和В,∅和○和0和O和0和0和0和0, 1和l和I和Ⅰ以及ᛁ和|和|和|,......

  • 不区分大小写的字符,如s和S和s, ss和Ss以及SS和ß和ẞ,......。< / p>

  • 所有数值的字符,与 1 的所有值相同:1¹11߁1111୧11౹౼1111111፩1៱᠑᥇᭑᮱᱁᱑⅟᭑᮱᱁᱑⅟①⑴⒈⒈⓵➀➀꘡꣑꤁꧑꩑꯱꘡꣑꤁꧑꩑꯱ ⅰⅰꛦ㆒㈠㊀。

  • 所有具有相同主要归类强度的字符,与所有与 d 相同的字符:DdÐðĎďĐđ◌ͩᴰᵈᶞ◌ᷘ◌ᷙḊḋḌḍḎḏḐḑḒḓⅅⅆⅮⅾⒹⓓꝹꝺDd 。请注意,其中一些不能通过任何类型的分解访问,但只能通过DUCET / UCA值;例如,相当常见的ð或新的ꝺ只能通过主UCA强度比较等同于d;与ƶ和z,ȼ和c等相同

  • 在某些区域设置中相同的字符,例如æ和ae,ä和ae,ä和aa,或麦金利和麦金利,......请注意,语言环境可以产生很大的不同,因为在某些语言环境中,c和ç是相同的字符,而在其他语言环境中它们不是;同样适用于n和ñ, a和á和ã,......。

其中一些可以处理。有些人不能。根据不同的需要,所有方法都需要不同的方法。

你的真正目标是什么?

答案 1 :(得分:11)

这不适用于所有条件,但摆脱大多数重音的一种方法是将字符转换为分解形式,然后丢弃组合重音:

# coding: utf8
import unicodedata as ud
s=u'U, Ù, Ú, Û, Ü, Ũ, Ū, Ŭ, Ů, Ű, Ų, Ư, Ǔ, Ǖ, Ǘ, Ǚ, Ǜ, Ụ, Ủ, Ứ, Ừ, Ử, Ữ, Ự'
print ud.normalize('NFD',s).encode('ascii','ignore')

输出

U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U

要查找重音字符,请使用以下内容:

import unicodedata as ud
import string

def asc(unichr):
    return ud.normalize('NFD',unichr).encode('ascii','ignore')

U = u''.join(unichr(i) for i in xrange(65536))
for c in string.letters:
    print u''.join(u for u in U if asc(u) == c)

输出

aàáâãäåāăąǎǟǡǻȁȃȧḁạảấầẩẫậắằẳẵặ
bḃḅḇ
cçćĉċčḉ
dďḋḍḏḑḓ
eèéêëēĕėęěȅȇȩḕḗḙḛḝẹẻẽếềểễệ
fḟ
 :
etc.

答案 2 :(得分:4)

为什么不将字形与这样的字形进行比较?

package similarglyphcharacterdetector;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class SimilarGlyphCharacterDetector {

    static char[] TEST_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890".toCharArray();
    static BufferedImage[] SAMPLES = null;

    public static BufferedImage drawGlyph(Font font, String string) {
        FontRenderContext frc = ((Graphics2D) new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY).getGraphics()).getFontRenderContext();

        Rectangle r= font.getMaxCharBounds(frc).getBounds();

        BufferedImage res = new BufferedImage(r.width, r.height, BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g = (Graphics2D) res.getGraphics();
        g.setBackground(Color.WHITE);
        g.fillRect(0, 0, r.width, r.height);
        g.setPaint(Color.BLACK);
        g.setFont(font);
        g.drawString(string, 0, r.height - font.getLineMetrics(string, g.getFontRenderContext()).getDescent());
        return res;
    }

    private static void drawSamples(Font f) {
        SAMPLES = new BufferedImage[TEST_CHARS.length];
        for (int i = 0; i < TEST_CHARS.length; i++)
            SAMPLES[i] = drawGlyph(f, String.valueOf(TEST_CHARS[i]));
    }

    private static int compareImages(BufferedImage img1, BufferedImage img2) {
        if (img1.getWidth() != img2.getWidth() || img1.getHeight() != img2.getHeight())
            throw new IllegalArgumentException();
        int d = 0;
        for (int y = 0; y < img1.getHeight(); y++) {
            for (int x = 0; x < img1.getWidth(); x++) {
                if (img1.getRGB(x, y) != img2.getRGB(x, y))
                    d++;
            }
        }
        return d;
    }

    private static int nearestSampleIndex(BufferedImage image, int maxDistance) {
        int best = Integer.MAX_VALUE;
        int bestIdx = -1;
        for (int i = 0; i < SAMPLES.length; i++) {
            int diff = compareImages(image, SAMPLES[i]);
            if (diff < best) {
                best = diff;
                bestIdx = i;
            }
        }
        if (best > maxDistance)
            return -1;
        return bestIdx;
    }

    public static void main(String[] args) throws Exception {
        Font f = new Font("FreeMono", Font.PLAIN, 13);
        drawSamples(f);
        HashMap<Character, StringBuilder> res = new LinkedHashMap<Character, StringBuilder>();
        for (char c : TEST_CHARS)
            res.put(c, new StringBuilder(String.valueOf(c)));
        int maxDistance = 5;
        for (int i = 0x80; i <= 0xFFFF; i++) {
            char c = (char)i;
            if (f.canDisplay(c)) {
                int n = nearestSampleIndex(drawGlyph(f, String.valueOf(c)), maxDistance);
                if (n != -1) {
                    char nc = TEST_CHARS[n];
                    res.get(nc).append(c);
                }
            }
        }
        for (Map.Entry<Character, StringBuilder> entry : res.entrySet())
            if (entry.getValue().length() > 1)
                System.out.println(entry.getValue());
    }
}

输出:

AÀÁÂÃÄÅĀĂĄǍǞȀȦΆΑΛАѦӒẠẢἈἉᾸᾹᾺᾼ₳Å
BƁƂΒБВЬḂḄḆ
CĆĈĊČƇΓЄГСὉℂⅭ
...