यूनिकोड वर्णों से विशिष्ट अंक (ń ǹ ñ ñ ņ marks marks marks marks marks marks marks (() निकालें


88

मैं एक एल्गोरिथ्म को देख रहा हूं, जो कि डिक्ट्रिटिक्स ( टिल्ड , राउंडफ्लेक्स , कैरेट , ओम्लूट , कैरन ) और उनके "सरल" चरित्र वाले पात्रों के बीच मैप कर सकता है ।

उदाहरण के लिए:

ń  ǹ  ň  ñ  ṅ  ņ  ṇ  ṋ  ṉ  ̈  ɲ  ƞ ᶇ ɳ ȵ  --> n
á --> a
ä --> a
ấ --> a
ṏ --> o

आदि।

  1. मैं जावा में ऐसा करना चाहता हूं, हालांकि मुझे संदेह है कि यह कुछ यूनिकोड-वाई होना चाहिए और किसी भी भाषा में आसानी से उचित होना चाहिए।

  2. उद्देश्य: आसानी से शब्दों के लिए खोज करने के लिए अनुमति देने के साथ। उदाहरण के लिए, यदि मेरे पास टेनिस खिलाड़ियों का एक डेटाबेस है, और Björn_Borg दर्ज किया गया है, तो मैं Bjorn_Borg भी रखूंगा ताकि मुझे यह पता चल सके कि कोई Bjorn में प्रवेश करता है और Björn नहीं।


यह इस बात पर निर्भर करता है कि आप किस वातावरण में प्रोग्रामिंग कर रहे हैं, हालांकि आपको मैन्युअल रूप से किसी प्रकार की मैपिंग टेबल को बनाए रखना होगा। तो, आप किस भाषा का उपयोग कर रहे हैं?
थोरिन

15
कृपया ध्यान रखें कि कुछ अक्षर जैसे ñ en.wikipedia.org/wiki/%C3%91 को खोजने के उद्देश्य से इसके डायट्रीक को नहीं छीनना चाहिए। Google स्पेनिश "एओ" (गुदा) और "एनो" (वर्ष) के बीच सही ढंग से अंतर करता है। इसलिए यदि आप वास्तव में एक अच्छा खोज इंजन चाहते हैं, तो आप बेसिक डिसीक्रिटिकल मार्क हटाने पर भरोसा नहीं कर सकते।
एडुआर्डो

@Eduardo: दिए गए संदर्भ में जो मायने नहीं रखता। ओपी द्वारा दिए गए उदाहरण का उपयोग करते हुए, एक व्यक्ति का नाम एक बहु-राष्ट्रीय संदर्भ में खोज रहा है जिसे आप वास्तव में चाहते हैं कि खोज बहुत सटीक न हो।
अमीर अबीरी

(दुर्घटनावश पिछले भेजे गए) ध्वन्यात्मक खोज में सुधार करने के लिए अपने ध्वन्यात्मक समकक्षों के लिए विकृति विज्ञान की मैपिंग के लिए कमरा है। यानी ñ => नी बेहतर परिणाम देगा अगर अंतर्निहित खोज इंजन ध्वन्यात्मक-आधारित (जैसे
साउंडेक्स

एक केस केस जिसमें
आनो को बदलकर एओ

जवाबों:


82

मैंने हाल ही में जावा में यह किया है:

public static final Pattern DIACRITICS_AND_FRIENDS
    = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");

private static String stripDiacritics(String str) {
    str = Normalizer.normalize(str, Normalizer.Form.NFD);
    str = DIACRITICS_AND_FRIENDS.matcher(str).replaceAll("");
    return str;
}

यह आपके द्वारा निर्दिष्ट के अनुसार होगा:

stripDiacritics("Björn")  = Bjorn

लेकिन यह उदाहरण के लिए Białystok पर विफल हो जाएगा, क्योंकि łचरित्र विशिष्ट नहीं है।

यदि आप एक पूर्ण विकसित स्ट्रिंग सरलीकरण करना चाहते हैं, तो आपको कुछ और विशेष वर्णों के लिए एक दूसरे क्लीनअप राउंड की आवश्यकता होगी, जो कि डायक्रिटिक्स नहीं हैं। क्या यह नक्शा है, मैंने सबसे आम विशेष पात्रों को शामिल किया है जो हमारे ग्राहक नामों में दिखाई देते हैं। यह पूरी सूची नहीं है, लेकिन यह आपको यह विचार देगा कि इसे कैसे बढ़ाया जाए। अचल संग्रह गूगल-संग्रह से सिर्फ एक सरल वर्ग है।

public class StringSimplifier {
    public static final char DEFAULT_REPLACE_CHAR = '-';
    public static final String DEFAULT_REPLACE = String.valueOf(DEFAULT_REPLACE_CHAR);
    private static final ImmutableMap<String, String> NONDIACRITICS = ImmutableMap.<String, String>builder()

        //Remove crap strings with no sematics
        .put(".", "")
        .put("\"", "")
        .put("'", "")

        //Keep relevant characters as seperation
        .put(" ", DEFAULT_REPLACE)
        .put("]", DEFAULT_REPLACE)
        .put("[", DEFAULT_REPLACE)
        .put(")", DEFAULT_REPLACE)
        .put("(", DEFAULT_REPLACE)
        .put("=", DEFAULT_REPLACE)
        .put("!", DEFAULT_REPLACE)
        .put("/", DEFAULT_REPLACE)
        .put("\\", DEFAULT_REPLACE)
        .put("&", DEFAULT_REPLACE)
        .put(",", DEFAULT_REPLACE)
        .put("?", DEFAULT_REPLACE)
        .put("°", DEFAULT_REPLACE) //Remove ?? is diacritic?
        .put("|", DEFAULT_REPLACE)
        .put("<", DEFAULT_REPLACE)
        .put(">", DEFAULT_REPLACE)
        .put(";", DEFAULT_REPLACE)
        .put(":", DEFAULT_REPLACE)
        .put("_", DEFAULT_REPLACE)
        .put("#", DEFAULT_REPLACE)
        .put("~", DEFAULT_REPLACE)
        .put("+", DEFAULT_REPLACE)
        .put("*", DEFAULT_REPLACE)

        //Replace non-diacritics as their equivalent characters
        .put("\u0141", "l") // BiaLystock
        .put("\u0142", "l") // Bialystock
        .put("ß", "ss")
        .put("æ", "ae")
        .put("ø", "o")
        .put("©", "c")
        .put("\u00D0", "d") // All Ð ð from http://de.wikipedia.org/wiki/%C3%90
        .put("\u00F0", "d")
        .put("\u0110", "d")
        .put("\u0111", "d")
        .put("\u0189", "d")
        .put("\u0256", "d")
        .put("\u00DE", "th") // thorn Þ
        .put("\u00FE", "th") // thorn þ
        .build();


    public static String simplifiedString(String orig) {
        String str = orig;
        if (str == null) {
            return null;
        }
        str = stripDiacritics(str);
        str = stripNonDiacritics(str);
        if (str.length() == 0) {
            // Ugly special case to work around non-existing empty strings
            // in Oracle. Store original crapstring as simplified.
            // It would return an empty string if Oracle could store it.
            return orig;
        }
        return str.toLowerCase();
    }

    private static String stripNonDiacritics(String orig) {
        StringBuffer ret = new StringBuffer();
        String lastchar = null;
        for (int i = 0; i < orig.length(); i++) {
            String source = orig.substring(i, i + 1);
            String replace = NONDIACRITICS.get(source);
            String toReplace = replace == null ? String.valueOf(source) : replace;
            if (DEFAULT_REPLACE.equals(lastchar) && DEFAULT_REPLACE.equals(toReplace)) {
                toReplace = "";
            } else {
                lastchar = toReplace;
            }
            ret.append(toReplace);
        }
        if (ret.length() > 0 && DEFAULT_REPLACE_CHAR == ret.charAt(ret.length() - 1)) {
            ret.deleteCharAt(ret.length() - 1);
        }
        return ret.toString();
    }

    /*
    Special regular expression character ranges relevant for simplification -> see http://docstore.mik.ua/orelly/perl/prog3/ch05_04.htm
    InCombiningDiacriticalMarks: special marks that are part of "normal" ä, ö, î etc..
        IsSk: Symbol, Modifier see http://www.fileformat.info/info/unicode/category/Sk/list.htm
        IsLm: Letter, Modifier see http://www.fileformat.info/info/unicode/category/Lm/list.htm
     */
    public static final Pattern DIACRITICS_AND_FRIENDS
        = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");


    private static String stripDiacritics(String str) {
        str = Normalizer.normalize(str, Normalizer.Form.NFD);
        str = DIACRITICS_AND_FRIENDS.matcher(str).replaceAll("");
        return str;
    }
}

about जैसे पात्रों के बारे में क्या?
मिकथोमप्सन

हालांकि वे पारित हो जाएंगे। इसी तरह सभी जापानी पात्रों आदि
एंड्रियास पीटरसन

धन्यवाद एंड्रियास। क्या इन्हें हटाने का कोई तरीका है? उत्पन्न स्ट्रिंग में 覚 が な を 男 or (या अन्य) जैसे वर्ण शामिल होंगे और ये मूल रूप से आउटपुट को तोड़ देंगे। मैं URL जनरेटर के रूप में सरलीकृत स्ट्रींग आउटपुट का उपयोग करने की कोशिश कर रहा हूं क्योंकि StackOverflow अपने प्रश्नों के URL के लिए करता है।
मिकथोमप्सन

2
जैसा कि मैंने प्रश्न टिप्पणी में कहा है। यदि आप एक अच्छा खोज इंजन चाहते हैं, तो आप बेसिक डिसक्रिटिकल मार्क हटाने पर भरोसा नहीं कर सकते।
एडुआर्डो

3
धन्यवाद एंड्रियास, एक आकर्षण की तरह काम करता है! (rrrr̈r'ŕřttẗţỳỹẙy'yýÿŷpp̈sss̈s̊s's̸śŝŞşšddd̈ďd'ḑf̈f̸ggg̈g'ģqĝǧḧĥj̈j'ḱkk̈k̸ǩlll̈Łłẅẍcc̈c̊c'c̸Çççćĉčvv̈v'v̸bb̧ǹnn̈n̊n'ńņňñmmmm̈m̊m̌ǵß पर परीक्षण) :-)
Fortega

25

कोर java.text पैकेज को इस उपयोग के मामले को संबोधित करने के लिए डिज़ाइन किया गया था (डायक्रिटिक्स, केस, आदि के बारे में देखभाल के बिना तार मिलान)।

वर्णों में अंतर Collatorपर सॉर्ट करने के लिए कॉन्फ़िगर करें PRIMARY। इसके साथ, CollationKeyप्रत्येक स्ट्रिंग के लिए बनाएं । यदि आपका सभी कोड जावा में है, तो आप CollationKeyसीधे उपयोग कर सकते हैं । यदि आपको किसी डेटाबेस या अन्य प्रकार के सूचकांक में कुंजियों को संग्रहीत करने की आवश्यकता है, तो आप इसे बाइट सरणी में बदल सकते हैं ।

ये वर्ग यूनिकोड मानक केस फोल्डिंग डेटा का उपयोग यह निर्धारित करने के लिए करते हैं कि कौन से अक्षर समान हैं, और विभिन्न अपघटन रणनीतियों का समर्थन करते हैं

Collator c = Collator.getInstance();
c.setStrength(Collator.PRIMARY);
Map<CollationKey, String> dictionary = new TreeMap<CollationKey, String>();
dictionary.put(c.getCollationKey("Björn"), "Björn");
...
CollationKey query = c.getCollationKey("bjorn");
System.out.println(dictionary.get(query)); // --> "Björn"

ध्यान दें कि कोलाटर स्थानीय-विशिष्ट हैं। ऐसा इसलिए है क्योंकि "वर्णमाला क्रम" स्थानों के बीच भिन्न होता है (और समय के साथ भी, जैसा कि स्पेनिश के साथ हुआ है)। Collatorवर्ग इन नियमों के सभी ट्रैक और तिथि करने के लिए उन्हें रखने के लिए होने से आप राहत मिलती है।


दिलचस्प लगता है, लेकिन क्या आप डेटाबेस में अपनी कोलाज़ कुंजी को चुनिंदा व्यक्ति से खोज सकते हैं, जहां 'bjo%' जैसे collated_name से ??
एंड्रियास पीटरसन

बहुत अच्छा, उस बारे में नहीं पता था। इसका प्रयास करेंगे।
एंड्रियास पीटरसन

Android पर CollationKeys का उपयोग डेटाबेस खोजों के लिए उपसर्गों के रूप में नहीं किया जा सकता है। स्ट्रिंग की एक कोलाज कुंजी aबाइट्स 41, 1, 5, 1, 5, 0 abमें बदल जाती है , फिर भी स्ट्रिंग बाइट्स 41, 43, 1, 6, 1, 6, 0. में बदल जाती है। ये बाइट सीक्वेंस इस प्रकार दिखाई नहीं देते हैं पूर्ण शब्दों में ( aab
कोलाज

1
@GrzegorzAdamHankiewicz कुछ परीक्षण के बाद, मैं देखता हूं कि बाइट सरणियों की तुलना की जा सकती है, लेकिन उपसर्गों का निर्माण न करें, जैसा कि आपने उल्लेख किया है। इसलिए, जैसे कि उपसर्ग क्वेरी करने के लिए bjo%, आपको एक श्रेणी क्वेरी करने की आवश्यकता होगी, जहां कोलर्स> = bjoऔर < bjp(या जो भी अगला प्रतीक उस लोकेल में होगा, और इसे निर्धारित करने के लिए कोई प्रोग्रामेटिक तरीका नहीं है)।
इरिकसन

16

यह अपाचे कॉमन्स लैंग का हिस्सा है । 3.1।

org.apache.commons.lang3.StringUtils.stripAccents("Añ");

रिटर्न An


1
For के लिए यह फिर से देता है
Ar

2
धन्यवाद माइक कि बाहर इशारा करने के लिए। विधि केवल लहजे को संभालती है। "Result ǹ ń of of ń ń ń ń ᶇ" का परिणाम है - "nnnnnnnnn ɲ ƞ ń ń
Kenston Choi

12

आप इस्तेमाल कर सकते हैं Normalizer वर्ग से java.text:

System.out.println(new String(Normalizer.normalize("ń ǹ ň ñ ṅ ņ ṇ ṋ", Normalizer.Form.NFKD).getBytes("ascii"), "ascii"));

लेकिन अभी भी कुछ काम करना बाकी है, क्योंकि जावा असंगत यूनिकोड वर्णों के साथ अजीब चीजें बनाता है (यह उन्हें अनदेखा नहीं करता है, और यह एक अपवाद नहीं फेंकता है)। लेकिन मुझे लगता है कि आप इसे एक शुरुआती बिंदु के रूप में इस्तेमाल कर सकते हैं।


3
यह गैर-असिसी डायक्रिटिक्स के लिए काम नहीं करेगा, जैसे कि रूसी में, उनके पास डियाट्रिक्टिक्स भी हैं, और इसके अलावा सभी एशियाई तार कसाई हैं। प्रयोग नहीं करें। Ascii में परिवर्तित करने के बजाय, \\ p {InCombiningDiacriticalMarks} का उपयोग करें, जैसा कि उत्तर में है stackoverflow.com/questions/1453171//
Andreas पीटरसन

10

एक मसौदा रिपोर्ट हैयूनिकोड वेबसाइट पर चरित्र तह पर जिसमें बहुत अधिक प्रासंगिक सामग्री है। विशेष रूप से धारा 4.1 देखें। "फोल्डिंग एल्गोरिथ्म"।

यहाँ एक चर्चा और कार्यान्वयन है पेर्ल का उपयोग करते हुए डिसरिटिक मार्कर हटाने की है।

ये मौजूदा SO प्रश्न संबंधित हैं:


5

कृपया ध्यान दें कि इन सभी चिह्नों में से कुछ "सामान्य" चरित्र पर सिर्फ "निशान" नहीं हैं, जिन्हें आप अर्थ को बदले बिना हटा सकते हैं।

स्वीडिश में, å ä और ö सही और उचित प्रथम श्रेणी के चरित्र हैं, कुछ अन्य चरित्र के "संस्करण" नहीं। वे सभी अन्य वर्णों से अलग ध्वनि करते हैं, वे अलग-अलग तरह के होते हैं, और वे शब्दों को अर्थ बदल देते हैं ("mätt" और "मैट" दो अलग-अलग शब्द हैं)।


4
हालांकि सही है, यह सवाल के जवाब की तुलना में अधिक टिप्पणी है।
साइमन फोर्सबर्ग

2

यूनिकोड में विशिष्ट डायट्रिक वर्ण होते हैं (जो मिश्रित वर्ण होते हैं) और एक स्ट्रिंग को परिवर्तित किया जा सकता है ताकि चरित्र और डायटिक्स अलग हो जाएं। उसके बाद, आप बस स्ट्रिंग से डायट जिलों को हटा सकते हैं और आप मूल रूप से कर रहे हैं।

सामान्यीकरण, डीकंपोज़िशन और समतुल्यता के बारे में अधिक जानकारी के लिए, यूनिकोड मानक को देखें यूनिकोड होम पेज पर देखें

हालांकि, आप वास्तव में इसे कैसे प्राप्त कर सकते हैं यह फ्रेमवर्क / ओएस / ... पर निर्भर करता है। यदि आप .NET का उपयोग कर रहे हैं, तो आप System.Text.NormalizationForm गणन को स्वीकार करते हुए String.Normalize विधि का उपयोग कर सकते हैं ।


2
यह वह विधि है जिसका उपयोग मैं .NET में करता हूं, हालांकि मुझे अभी भी कुछ पात्रों को मैन्युअल रूप से मैप करना है। वे डिआट्रियाटिक नहीं हैं, लेकिन डिग्राफ हैं। हालांकि इसी तरह की समस्या।
थोरिन

1
सामान्यीकरण फ़ॉर्म "डी" (यानी विघटित) में परिवर्तित करें और आधार चरित्र लें।
रिचर्ड

2

सबसे आसान तरीका (मेरे लिए) बस एक विरल मानचित्रण सरणी बनाए रखना होगा जो बस आपके यूनिकोड कोड बिंदुओं को डिस्प्ले स्ट्रिंग्स में बदलता है।

जैसे कि:

start    = 0x00C0
size     = 23
mappings = {
    "A","A","A","A","A","A","AE","C",
    "E","E","E","E","I","I","I", "I",
    "D","N","O","O","O","O","O"
}
start    = 0x00D8
size     = 6
mappings = {
    "O","U","U","U","U","Y"
}
start    = 0x00E0
size     = 23
mappings = {
    "a","a","a","a","a","a","ae","c",
    "e","e","e","e","i","i","i", "i",
    "d","n","o","o","o","o","o"
}
start    = 0x00F8
size     = 6
mappings = {
    "o","u","u","u","u","y"
}
: : :

एक विरल सरणी का उपयोग आपको यूनिकोड तालिका के व्यापक रूप से स्थानिक वर्गों में भी कुशलता से प्रतिस्थापन का प्रतिनिधित्व करने की अनुमति देगा। स्ट्रिंग प्रतिस्थापन आपके मनोदशाओं को बदलने के लिए मनमाने ढंग से अनुक्रमों की अनुमति देगा (जैसे कि æअंगूर बनना ae)।

यह एक भाषा-अज्ञेयवादी उत्तर है, इसलिए, यदि आपके पास एक विशिष्ट भाषा है, तो बेहतर तरीके होंगे (हालांकि वे सभी संभवत: इस तरह से सबसे कम स्तर पर नीचे आ जाएंगे)।


सभी संभव अजीब पात्रों को जोड़ना एक आसान काम नहीं है। केवल कुछ पात्रों के लिए ऐसा करते समय, यह एक अच्छा समाधान है।
साइमन फोर्सबर्ग

2

कुछ विचार करने के लिए: यदि आप प्रत्येक शब्द का एक "अनुवाद" प्राप्त करने का प्रयास करते हैं, तो आप कुछ संभावित विकल्पों को याद कर सकते हैं।

उदाहरण के लिए, जर्मन में, "एस-सेट" की जगह, कुछ लोग "बी" का उपयोग कर सकते हैं, जबकि अन्य "एसएस" का उपयोग कर सकते हैं। या, "o" या "oe" के साथ एक umlauted o की जगह। आदर्श रूप से आपके पास कोई भी समाधान, मुझे लगता है कि दोनों को शामिल करना चाहिए।


2

Windows और .NET में, मैं सिर्फ स्ट्रिंग एन्कोडिंग का उपयोग करके परिवर्तित करता हूं। इस तरह मैं मैनुअल मैपिंग और कोडिंग से बचता हूं।

स्ट्रिंग एन्कोडिंग के साथ खेलने का प्रयास करें।


3
आप स्ट्रिंग एन्कोडिंग पर विस्तृत कर सकते हैं? उदाहरण के लिए, एक कोड उदाहरण के साथ।
पीटर मोर्टेंसन

2

जर्मन के मामले में यह उमलाट्स (ä, ö, ü) से विकृति विज्ञान को दूर नहीं करना चाहता था। इसके बजाय उन्हें दो अक्षर संयोजन (ae, oe, ue) द्वारा प्रतिस्थापित किया जाता है। उदाहरण के लिए, Björn को Bjoern (ब्योर्न नहीं) के रूप में लिखा जाना चाहिए ताकि सही उच्चारण हो सके।

इसके लिए मेरे पास हार्डकोडेड मैपिंग होगी, जहां आप प्रत्येक विशेष वर्ण समूह के लिए व्यक्तिगत रूप से प्रतिस्थापन नियम को परिभाषित कर सकते हैं।


0

भविष्य के संदर्भ के लिए, यहां C # एक्सटेंशन पद्धति है जो लहजे को हटाती है।

public static class StringExtensions
{
    public static string RemoveDiacritics(this string str)
    {
        return new string(
            str.Normalize(NormalizationForm.FormD)
                .Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != 
                            UnicodeCategory.NonSpacingMark)
                .ToArray());
    }
}
static void Main()
{
    var input = "ŃŅŇ ÀÁÂÃÄÅ ŢŤţť Ĥĥ àáâãäå ńņň";
    var output = input.RemoveDiacritics();
    Debug.Assert(output == "NNN AAAAAA TTtt Hh aaaaaa nnn");
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.