Найти символы, которые похожи глифически в Unicode?
Допустим, у меня есть персонажи Ú, Ù, Ü. Все они похожи по языку на английский U.
Есть ли какой-то список или алгоритм для этого:
- Если Ú или Ù или Ü вернуть английский U
- Учитывая английский U, вернуть список всех U-подобных символов
Я не уверен, что кодовая точка символов Unicode одинакова для всех шрифтов? Если это так, я полагаю, может быть какой-то простой и эффективный способ сделать это?
ОБНОВИТЬ
Если вы используете Ruby, для этого существует доступный для юникода гем, который может помочь в некоторых случаях.
3 ответа
Это не будет работать для всех условий, но один из способов избавиться от большинства акцентов - это преобразовать символы в их разложенную форму, а затем выбросить объединяющие акценты:
# 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.
Очень неясно, что вы просите здесь сделать.
Существуют символы, все канонические разложения которых начинаются с одного и того же базового символа: e, é, ê, ë, ē, ĕ, ė, ę, ě, ȅ, ȇ, ȩ, ḕ, ḗ, ḙ, ḛ, ḝ, ẹ, ẻ, ẽ, ế, ề, ể, ễ, ễ, ệ, e̳, … или s, ś, ŝ, ş, š, ș, ṡ, ṣ, ṥ, ṧ, ṩ, ….
Существуют символы, все разложения совместимости которых включают в себя определенный символ: ᵉ, ₑ, ℯ, ⅇ, ⒠, ⓔ, ㋍, ㋎, e, … или s, ſ, ˢ, ẛ, ₨, ℁, ⒮, ⓢ, ㎧, ㎨, ㎮, ㎯, ㎰, ㎱, ㎲, ㎲, ㎳, ㏛, ſt, st, s, … или R, ᴿ, ₨, ℛ, ℜ, ℝ, Ⓡ, ㏚, R, ….
В некоторых шрифтах есть символы, которые похожи друг на друга: ß и β и ϐ, или 3 и Ʒ и Ʒ и Ȝ и ʒ и ӡ и ᴣ, или ɣ и ɤ и γ, или F и Ϝ и ϝ, или B и Β и В, или ∅ и ○ и 0 и О и and и ০ и ੦ и ౦ и ૦, или 1 и l и I и and и ᛁ и | и ǀ и ∣, ….
Символы, которые одинаковы без учета регистра, такие как s и S и ſ, или ss и Ss и SS и ß и ẞ, ….
Символы, которые имеют одинаковое числовое значение, как и все они для значения 1: 1 ¹١۱߁१১੧૧ ㈠㊀ ௧౧౹౼೧൧๑໑༡၁႑ ១៱᠑ ᠑ ᥇ ᭑᮱᱁᱑₁⅟ ᭑᮱᱁᱑₁⅟ ⓵ ⓵ ⓵ ㈠㊀ ㈠㊀.
Символы, которые имеют одинаковую первичную силу сопоставления, как и все те же, что и d: DdÐðĎďĐđ◌ͩᴰᵈᶞ◌ᷘ◌ᷙḊḋḌḍḎḏḐḑḒḓⅅⅆⅮⅾ Ⓓ ⓓ ꝹꝺDd. Обратите внимание, что некоторые из них недоступны при любом виде декомпозиции, но только через значения DUCET/UCA; например, довольно распространенный ð или новый ꝺ может быть приравнен к d только посредством первичного сравнения силы UCA; то же самое с ƶ и z, ȼ и с и т. д.
Символы, которые являются одинаковыми в определенных локалях, такие как æ и ae, или ä и ae, или ä и aa, или MacKinley и McKinley, …. Обратите внимание, что локаль может иметь действительно большое значение, так как в некоторых локалях символы c и ç являются одним и тем же символом, а в других - нет; аналогично для n и ñ, или a и á и ã, ….
Некоторые из них могут быть обработаны. Некоторые не могут. Все требуют разных подходов в зависимости от разных потребностей.
Какова ваша настоящая цель?
Почему бы просто не сравнить глифы с чем-то вроде этого?
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ĆĈĊČƇΓЄГСὉℂⅭ
...