.NET의 문자열에서 분음 부호 (악센트)를 어떻게 제거합니까?


433

프랑스어 프랑스어로 된 일부 문자열을 변환하려고하는데 기본적으로 문자를 유지하면서 문자에서 프랑스어 악센트 표시를 가져올 수 있기를 원합니다. (예 : 변환을 é하기 e때문에 crème brûlée될 것입니다 creme brulee)

이것을 달성하는 가장 좋은 방법은 무엇입니까?


14
경고 :이 방법은 특정 경우에 작동 할 수 있지만 일반적으로 분음 부호를 제거 할 수는 없습니다. 경우에 따라 일부 언어에서는 텍스트의 의미가 변경 될 수 있습니다. 왜 이런 일을하고 싶은지는 말하지 않습니다. 문자열을 비교하거나 검색하기 위해 유니 코드 인식 라이브러리를 사용하는 것이 가장 좋습니다.
JacquesB

1
이를 달성하기위한 대부분의 기술은 유니 코드 정규화에 의존하기 때문에 표준을 설명하는이 문서를 읽는 것이 유용 할 수 있습니다. unicode.org/reports/tr15
LuddyPants

Azure 팀에서이 문제를 해결했다고 생각하고 이름이 "Mémo de la réunion.pdf"인 파일을 업로드하려고했지만 작업이 성공했습니다.
Rady

답변:


532

나는이 방법을 사용하지 않는했지만, 마이클 카플란 (혼란 제목으로) 자신의 블로그 게시물에서 그렇게 발음 구별 부호를 제거에 대한 그 회담을하는 방법을 설명합니다 스트립은, 일명 의미의 의미에 흥미로운 작업 (모든 망간 문자 일명 간격을 두지 않지만 일부는 간격을 두지 않습니다.)

static string RemoveDiacritics(string text) 
{
    var normalizedString = text.Normalize(NormalizationForm.FormD);
    var stringBuilder = new StringBuilder();

    foreach (var c in normalizedString)
    {
        var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
        if (unicodeCategory != UnicodeCategory.NonSpacingMark)
        {
            stringBuilder.Append(c);
        }
    }

    return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}

이것은 그의 이전 게시물에 대한 후속 조치입니다. 스트립 분음 부호 ....

이 접근법은 String.Normalize 를 하여 입력 문자열을 구성 글리프 (기본적으로 "기본"문자를 분음 부호로 분리)로 분할 한 다음 결과를 스캔하고 기본 문자 만 유지합니다. 조금 복잡하지만 실제로는 복잡한 문제를보고 있습니다.

물론 프랑스어로 자신을 제한하는 경우 @David Dibben에서 권장하는 것처럼 C ++ std :: string에서 악센트 및 물결표를 제거하는 방법에서 간단한 테이블 기반 접근 방식을 사용하지 못할 수 있습니다.


32
이것은 잘못이다. 독일어 문자 ä 및 ö 및 ü는 ae ue가 아닌 ae ue 및 oe로 라틴어로 표시됩니다.
Stefan Steiger

20
또한 폴란드어 문자 ł는 무시됩니다.
Zbigniew Wiadro

4
또한 Norse ø는 무시됩니다
Richard de Wit

28
@StefanSteiger 아시다시피, 체코 어에는 áčěů와 같은 글자가 있는데, 다른 소리로 들리더라도 "hrábě"/ hra : bje /, "hrabě"/ hrabje /, 및 "hrabe"/ hrabe /. 나에게 발음 구별 부호의 삭제는 문자의 발음이나 역사에 무관심한 순수한 그래픽 문제인 것 같습니다. ä ö ü와 같은 문자는 기본 문자에 위첨자 "e"를 추가하여 만들어 졌으므로 "ae"분해는 역사적으로 의미가 있습니다. 그래픽 마크를 제거하거나 문자를 ASCII 문자로 분해하는 목표에 달려 있습니다.
IllidanS4는 Monica를

10
이 기능은 언어에 구애받지 않습니다. 문자열이 독일어인지 다른 언어인지는 알 수 없습니다. 독일어 텍스트에서 oe를 oe로 바꾸는 것이 좋다고 생각하지만 터키어로는 타당하지 않다면 언어를 감지하지 못하면이 문제를 해결할 수 없다는 것을 알 수 있습니다.
thorn̈

163

이것은 나를 위해 트릭을했다 ...

string accentedStr;
byte[] tempBytes;
tempBytes = System.Text.Encoding.GetEncoding("ISO-8859-8").GetBytes(accentedStr);
string asciiStr = System.Text.Encoding.UTF8.GetString(tempBytes);

빠른 & 짧은!


9
이것은 내가 본 가장 좋은 방법입니다.
Cleiton

2
이 솔루션이 마음에 들며 Windows 스토어 앱에서 잘 작동합니다. 그러나 ISO-8859-8 인코딩을 사용할 수없는 것처럼 보이기 때문에 Windows Phone Apps에서는 작동하지 않습니다. 대신 사용할 수있는 다른 인코딩이 있습니까?
Philip Colmer

2
이것은 가장 일반적인 문자에서 작동하지만 « »and (단일 문자로) 와 같은 많은 특수 문자 는 허용되는 솔루션의 경우와 다른 프로세스에서 변경됩니다.
The_Black_Smurf

7
Linux의 .NET Core에서는 작동하지 않습니다.System.ArgumentException: 'ISO-8859-8' is not a supported encoding name.
EM0

2
.NET Core를 사용 System.Text.Encoding.CodePages하는 경우 nuget 에서 설치 한 후 전화를 걸어 공급자를 등록하십시오 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);.-이 작업을
마치면

32

누군가 관심이 있다면 비슷한 것을 찾고 있었고 다음과 같이 작성하지 않았습니다.

public static string NormalizeStringForUrl(string name)
{
    String normalizedString = name.Normalize(NormalizationForm.FormD);
    StringBuilder stringBuilder = new StringBuilder();

    foreach (char c in normalizedString)
    {
        switch (CharUnicodeInfo.GetUnicodeCategory(c))
        {
            case UnicodeCategory.LowercaseLetter:
            case UnicodeCategory.UppercaseLetter:
            case UnicodeCategory.DecimalDigitNumber:
                stringBuilder.Append(c);
                break;
            case UnicodeCategory.SpaceSeparator:
            case UnicodeCategory.ConnectorPunctuation:
            case UnicodeCategory.DashPunctuation:
                stringBuilder.Append('_');
                break;
        }
    }
    string result = stringBuilder.ToString();
    return String.Join("_", result.Split(new char[] { '_' }
        , StringSplitOptions.RemoveEmptyEntries)); // remove duplicate underscores
}

9
메모리 할당 오버 헤드를 최소화하려면 StringBuilder 버퍼를 이름에 미리 할당해야합니다. 순차적 복제 _를 제거하기위한 마지막 Split / Join 호출이 흥미 롭습니다. 아마도 우리는 루프에 추가하지 않아야합니다. 이전 문자의 플래그를 _로 설정하고 true 인 경우에는 플래그를 방출하지 않습니다.
IDisposable

2 정말 좋은 점은 코드 의이 부분으로 돌아갈 시간이 있다면 다시 작성하겠습니다. :)
Luk

좋은. IDisposables 주석 외에도 c < 128UTF 문자를 픽업하지 않도록 확인해야합니다 ( 여기 참조) .
Christian Gollhardt

1
또는 아마도 더 효율적 c < 123입니다. ASCI
Christian Gollhardt

여전히 ø와 같은 문자로는 작동하지 않습니다.
juanora

27

모든 주요 유니 코드 문자를 변환 할 수있는 것이 필요했으며 투표 된 답변은 몇 가지를 제외하고 CodeIgniter 버전을 convert_accented_characters($str)쉽게 사용자 정의 할 수있는 C #으로 만들었습니다 .

using System;
using System.Text;
using System.Collections.Generic;

public static class Strings
{
    static Dictionary<string, string> foreign_characters = new Dictionary<string, string>
    {
        { "äæǽ", "ae" },
        { "öœ", "oe" },
        { "ü", "ue" },
        { "Ä", "Ae" },
        { "Ü", "Ue" },
        { "Ö", "Oe" },
        { "ÀÁÂÃÄÅǺĀĂĄǍΑΆẢẠẦẪẨẬẰẮẴẲẶА", "A" },
        { "àáâãåǻāăąǎªαάảạầấẫẩậằắẵẳặа", "a" },
        { "Б", "B" },
        { "б", "b" },
        { "ÇĆĈĊČ", "C" },
        { "çćĉċč", "c" },
        { "Д", "D" },
        { "д", "d" },
        { "ÐĎĐΔ", "Dj" },
        { "ðďđδ", "dj" },
        { "ÈÉÊËĒĔĖĘĚΕΈẼẺẸỀẾỄỂỆЕЭ", "E" },
        { "èéêëēĕėęěέεẽẻẹềếễểệеэ", "e" },
        { "Ф", "F" },
        { "ф", "f" },
        { "ĜĞĠĢΓГҐ", "G" },
        { "ĝğġģγгґ", "g" },
        { "ĤĦ", "H" },
        { "ĥħ", "h" },
        { "ÌÍÎÏĨĪĬǏĮİΗΉΊΙΪỈỊИЫ", "I" },
        { "ìíîïĩīĭǐįıηήίιϊỉịиыї", "i" },
        { "Ĵ", "J" },
        { "ĵ", "j" },
        { "ĶΚК", "K" },
        { "ķκк", "k" },
        { "ĹĻĽĿŁΛЛ", "L" },
        { "ĺļľŀłλл", "l" },
        { "М", "M" },
        { "м", "m" },
        { "ÑŃŅŇΝН", "N" },
        { "ñńņňʼnνн", "n" },
        { "ÒÓÔÕŌŎǑŐƠØǾΟΌΩΏỎỌỒỐỖỔỘỜỚỠỞỢО", "O" },
        { "òóôõōŏǒőơøǿºοόωώỏọồốỗổộờớỡởợо", "o" },
        { "П", "P" },
        { "п", "p" },
        { "ŔŖŘΡР", "R" },
        { "ŕŗřρр", "r" },
        { "ŚŜŞȘŠΣС", "S" },
        { "śŝşșšſσςс", "s" },
        { "ȚŢŤŦτТ", "T" },
        { "țţťŧт", "t" },
        { "ÙÚÛŨŪŬŮŰŲƯǓǕǗǙǛŨỦỤỪỨỮỬỰУ", "U" },
        { "ùúûũūŭůűųưǔǖǘǚǜυύϋủụừứữửựу", "u" },
        { "ÝŸŶΥΎΫỲỸỶỴЙ", "Y" },
        { "ýÿŷỳỹỷỵй", "y" },
        { "В", "V" },
        { "в", "v" },
        { "Ŵ", "W" },
        { "ŵ", "w" },
        { "ŹŻŽΖЗ", "Z" },
        { "źżžζз", "z" },
        { "ÆǼ", "AE" },
        { "ß", "ss" },
        { "IJ", "IJ" },
        { "ij", "ij" },
        { "Œ", "OE" },
        { "ƒ", "f" },
        { "ξ", "ks" },
        { "π", "p" },
        { "β", "v" },
        { "μ", "m" },
        { "ψ", "ps" },
        { "Ё", "Yo" },
        { "ё", "yo" },
        { "Є", "Ye" },
        { "є", "ye" },
        { "Ї", "Yi" },
        { "Ж", "Zh" },
        { "ж", "zh" },
        { "Х", "Kh" },
        { "х", "kh" },
        { "Ц", "Ts" },
        { "ц", "ts" },
        { "Ч", "Ch" },
        { "ч", "ch" },
        { "Ш", "Sh" },
        { "ш", "sh" },
        { "Щ", "Shch" },
        { "щ", "shch" },
        { "ЪъЬь", "" },
        { "Ю", "Yu" },
        { "ю", "yu" },
        { "Я", "Ya" },
        { "я", "ya" },
    };

    public static char RemoveDiacritics(this char c){
        foreach(KeyValuePair<string, string> entry in foreign_characters)
        {
            if(entry.Key.IndexOf (c) != -1)
            {
                return entry.Value[0];
            }
        }
        return c;
    }

    public static string RemoveDiacritics(this string s) 
    {
        //StringBuilder sb = new StringBuilder ();
        string text = "";


        foreach (char c in s)
        {
            int len = text.Length;

            foreach(KeyValuePair<string, string> entry in foreign_characters)
            {
                if(entry.Key.IndexOf (c) != -1)
                {
                    text += entry.Value;
                    break;
                }
            }

            if (len == text.Length) {
                text += c;  
            }
        }
        return text;
    }
}

용법

// for strings
"crème brûlée".RemoveDiacritics (); // creme brulee

// for chars
"Ã"[0].RemoveDiacritics (); // A

5
구현은 작업을 수행하지만 프로덕션 코드에서 사용하기 전에 개선해야합니다.
Pierre Arnaud


왜 이것을 이것을 다음 if (entry.Key.IndexOf(c) != -1)으로 대체하지 if (entry.Key.Contains(c))
않겠습니까

루프에서 RemoveDiacritics (char c)를 다시 사용하지 말고 StringBuilder를 사용하지 않는 이유는 무엇입니까? 나는 복잡한 사전 및 작업 솔루션을 upvote에,하지만 코드는 훨씬 간단 수
파블 Cioch

1
왜 전화 를 걸지 { "äæǽ", "ae" }않고 대신 뛰어 넘기고 많은 농구 대가 있는지 이해가되지 않습니다 . 사전에 이미있는 색인의 목적을 완전히 물리 쳤습니다. { "ä", "ae" }, { "æ", "ae" }, { "ǽ", "ae" }if (foreign_characters.TryGetValue(...)) ...
베이컨 비트

15

관심있는 사람은 다음과 같습니다.

import java.text.Normalizer;

public class MyClass
{
    public static String removeDiacritics(String input)
    {
        String nrml = Normalizer.normalize(input, Normalizer.Form.NFD);
        StringBuilder stripped = new StringBuilder();
        for (int i=0;i<nrml.length();++i)
        {
            if (Character.getType(nrml.charAt(i)) != Character.NON_SPACING_MARK)
            {
                stripped.append(nrml.charAt(i));
            }
        }
        return stripped.toString();
    }
}

3
벗겨진 + = nrml.charAt (i) 대신 StringBuilder를 사용하십시오. 여기에 O (n²) 런타임이 숨겨져 있습니다.
Andreas Petersson

6
여기 및 다른 Java 답변은이 스레드를 혼란스럽게합니다. 질문은 Java가 아닌 C # (.NET)에 관한 것입니다!
suchoss

15

여기에서 찾은 다른 버전을 기반으로 확장 방법을 사용하는 경우가 많습니다 ( C #에서 문자 교체 (ascii) 참조 ).

  • D를 형성하기 위해 정규화하는 것은 è 와 같은 문자 를 e로 나누고 공백이없는 `
  • 이것으로부터 nospacing 문자가 제거됩니다
  • 결과는 C로 다시 정규화됩니다 (필요한지 확실하지 않습니다)

암호:

using System.Linq;
using System.Text;
using System.Globalization;

// namespace here
public static class Utility
{
    public static string RemoveDiacritics(this string str)
    {
        if (null == str) return null;
        var chars =
            from c in str.Normalize(NormalizationForm.FormD).ToCharArray()
            let uc = CharUnicodeInfo.GetUnicodeCategory(c)
            where uc != UnicodeCategory.NonSpacingMark
            select c;

        var cleanStr = new string(chars.ToArray()).Normalize(NormalizationForm.FormC);

        return cleanStr;
    }

    // or, alternatively
    public static string RemoveDiacritics2(this string str)
    {
        if (null == str) return null;
        var chars = str
            .Normalize(NormalizationForm.FormD)
            .ToCharArray()
            .Where(c=> CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
            .ToArray();

        return new string(chars).Normalize(NormalizationForm.FormC);
    }
}

9

그리스어 코드 페이지 (ISO)로 가능

이 코드 페이지에 대한 정보는에 System.Text.Encoding.GetEncodings()있습니다. 에서 배우십시오 :https://msdn.microsoft.com/pt-br/library/system.text.encodinginfo.getencoding(v=vs.110).aspx

그리스어 (ISO)의 코드 페이지는 28597 이며 이름은 iso-8859-7입니다. 입니다.

코드로 이동 ... \ o /

string text = "Você está numa situação lamentável";

string textEncode = System.Web.HttpUtility.UrlEncode(text, Encoding.GetEncoding("iso-8859-7"));
//result: "Voce+esta+numa+situacao+lamentavel"

string textDecode = System.Web.HttpUtility.UrlDecode(textEncode);
//result: "Voce esta numa situacao lamentavel"

이 함수를 작성하십시오.

public string RemoveAcentuation(string text)
{
    return
        System.Web.HttpUtility.UrlDecode(
            System.Web.HttpUtility.UrlEncode(
                text, Encoding.GetEncoding("iso-8859-7")));
}

첫 번째는 이름이고 두 번째는 인코딩의 코드 페이지이기 때문에 ... Encoding.GetEncoding("iso-8859-7")과 같습니다 Encoding.GetEncoding(28597).


3
훌륭합니다! 짧고 효율적입니다!
krlzlx

1
좋은 물건. 테스트 한 거의 모든 문자가 통과되었습니다. ( äáčďěéíľľňôóřŕšťúůýž ÄÁČĎĚÉÍĽĽŇÔÓŘŔŠŤÚŮÝŽ ÖÜË łŁđĐ ţŢşŞçÇ øı). 문제점은 발견 된 ßə로 변환되는, ?그러나 그러한 예외는 항상 별도의 방법으로 처리 할 수 있습니다. 이것을 프로덕션에 적용하기 전에 분음 부호가있는 문자가 포함 된 모든 유니 코드 영역에 대해 테스트를 더 잘 수행해야합니다.
miroxlav

5

그런 질문에 너무 많은 답변을 얻을 수 있지만 아직 내 요구 사항에 맞지 않는 것이 재미 있습니다.

원래 질문은 프랑스어와 관련이 있었으므로 가장 간단한 작업 답변은 실제로

    public static string ConvertWesternEuropeanToASCII(this string str)
    {
        return Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(str));
    }

1251은 입력 언어의 인코딩 코드로 대체되어야합니다.

그러나 이것은 하나의 문자 만 하나의 문자로 대체합니다. 독일어로 입력 작업을하고 있기 때문에 수동 변환을 수행했습니다.

    public static string LatinizeGermanCharacters(this string str)
    {
        StringBuilder sb = new StringBuilder(str.Length);
        foreach (char c in str)
        {
            switch (c)
            {
                case 'ä':
                    sb.Append("ae");
                    break;
                case 'ö':
                    sb.Append("oe");
                    break;
                case 'ü':
                    sb.Append("ue");
                    break;
                case 'Ä':
                    sb.Append("Ae");
                    break;
                case 'Ö':
                    sb.Append("Oe");
                    break;
                case 'Ü':
                    sb.Append("Ue");
                    break;
                case 'ß':
                    sb.Append("ss");
                    break;
                default:
                    sb.Append(c);
                    break;
            }
        }
        return sb.ToString();
    }

최상의 성능을 제공하지는 못하지만 최소한 읽고 쉽게 확장 할 수 있습니다. 정규식은 NO GO로, 어떤 char / string보다 훨씬 느립니다.

또한 공간을 제거하는 매우 간단한 방법이 있습니다.

    public static string RemoveSpace(this string str)
    {
        return str.Replace(" ", string.Empty);
    }

결국, 나는 위의 세 가지 확장의 조합을 사용하고 있습니다 :

    public static string LatinizeAndConvertToASCII(this string str, bool keepSpace = false)
    {
        str = str.LatinizeGermanCharacters().ConvertWesternEuropeanToASCII();            
        return keepSpace ? str : str.RemoveSpace();
    }

그리고 성공적으로 통과하는 작은 단위 테스트 (완전하지는 않음).

    [TestMethod()]
    public void LatinizeAndConvertToASCIITest()
    {
        string europeanStr = "Bonjour ça va? C'est l'été! Ich möchte ä Ä á à â ê é è ë Ë É ï Ï î í ì ó ò ô ö Ö Ü ü ù ú û Û ý Ý ç Ç ñ Ñ";
        string expected = "Bonjourcava?C'estl'ete!IchmoechteaeAeaaaeeeeEEiIiiiooooeOeUeueuuuUyYcCnN";
        string actual = europeanStr.LatinizeAndConvertToASCII();
        Assert.AreEqual(expected, actual);
    }

4

이것은 자바에서 잘 작동합니다.

기본적으로 악센트 부호가있는 모든 문자를 악센트 부호가없는 상대 문자로 변환 한 다음 분음 부호를 조합합니다. 이제 정규 표현식을 사용하여 분음 부호를 제거 할 수 있습니다.

import java.text.Normalizer;
import java.util.regex.Pattern;

public String deAccent(String str) {
    String nfdNormalizedString = Normalizer.normalize(str, Normalizer.Form.NFD); 
    Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
    return pattern.matcher(nfdNormalizedString).replaceAll("");
}

또는 자바 7,"\\p{Block=CombiningDiacriticalMarks}"
브렌트 파우스트

11
질문에 구체적으로 .NET을 요청할 때 왜 Java 솔루션을 게시 하시겠습니까?
David

2
@David이 질문은 "java drop accents"에 대한 Google의 인기 질문입니다. 여기에 속하지는 않지만 여기서 유용합니다.
blubb

3

TL; DR- C # 문자열 확장 방법

문자열의 의미를 유지하는 가장 좋은 해결책은 문자를 제거하는 대신 변환하는 것입니다.이 예제 crème brûlée에서 crme brlevs.로 잘 설명되어 creme brulee있습니다.

위의 Alexander의 의견을 확인하고 Lucene.Net 코드에 Apache 2.0 라이센스가 부여되어 클래스를 간단한 문자열 확장 메소드로 수정했습니다. 다음과 같이 사용할 수 있습니다.

var originalString = "crème brûlée";
var maxLength = originalString.Length; // limit output length as necessary
var foldedString = originalString.FoldToASCII(maxLength); 
// "creme brulee"

함수가 너무 길어서 StackOverflow 답변에 게시 할 수 없습니다 (~ 139k 문자 30k 허용 lol) 그래서 요점을 작성하고 저자를 평가했습니다 .

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// <summary>
/// This class converts alphabetic, numeric, and symbolic Unicode characters
/// which are not in the first 127 ASCII characters (the "Basic Latin" Unicode
/// block) into their ASCII equivalents, if one exists.
/// <para/>
/// Characters from the following Unicode blocks are converted; however, only
/// those characters with reasonable ASCII alternatives are converted:
/// 
/// <ul>
///   <item><description>C1 Controls and Latin-1 Supplement: <a href="http://www.unicode.org/charts/PDF/U0080.pdf">http://www.unicode.org/charts/PDF/U0080.pdf</a></description></item>
///   <item><description>Latin Extended-A: <a href="http://www.unicode.org/charts/PDF/U0100.pdf">http://www.unicode.org/charts/PDF/U0100.pdf</a></description></item>
///   <item><description>Latin Extended-B: <a href="http://www.unicode.org/charts/PDF/U0180.pdf">http://www.unicode.org/charts/PDF/U0180.pdf</a></description></item>
///   <item><description>Latin Extended Additional: <a href="http://www.unicode.org/charts/PDF/U1E00.pdf">http://www.unicode.org/charts/PDF/U1E00.pdf</a></description></item>
///   <item><description>Latin Extended-C: <a href="http://www.unicode.org/charts/PDF/U2C60.pdf">http://www.unicode.org/charts/PDF/U2C60.pdf</a></description></item>
///   <item><description>Latin Extended-D: <a href="http://www.unicode.org/charts/PDF/UA720.pdf">http://www.unicode.org/charts/PDF/UA720.pdf</a></description></item>
///   <item><description>IPA Extensions: <a href="http://www.unicode.org/charts/PDF/U0250.pdf">http://www.unicode.org/charts/PDF/U0250.pdf</a></description></item>
///   <item><description>Phonetic Extensions: <a href="http://www.unicode.org/charts/PDF/U1D00.pdf">http://www.unicode.org/charts/PDF/U1D00.pdf</a></description></item>
///   <item><description>Phonetic Extensions Supplement: <a href="http://www.unicode.org/charts/PDF/U1D80.pdf">http://www.unicode.org/charts/PDF/U1D80.pdf</a></description></item>
///   <item><description>General Punctuation: <a href="http://www.unicode.org/charts/PDF/U2000.pdf">http://www.unicode.org/charts/PDF/U2000.pdf</a></description></item>
///   <item><description>Superscripts and Subscripts: <a href="http://www.unicode.org/charts/PDF/U2070.pdf">http://www.unicode.org/charts/PDF/U2070.pdf</a></description></item>
///   <item><description>Enclosed Alphanumerics: <a href="http://www.unicode.org/charts/PDF/U2460.pdf">http://www.unicode.org/charts/PDF/U2460.pdf</a></description></item>
///   <item><description>Dingbats: <a href="http://www.unicode.org/charts/PDF/U2700.pdf">http://www.unicode.org/charts/PDF/U2700.pdf</a></description></item>
///   <item><description>Supplemental Punctuation: <a href="http://www.unicode.org/charts/PDF/U2E00.pdf">http://www.unicode.org/charts/PDF/U2E00.pdf</a></description></item>
///   <item><description>Alphabetic Presentation Forms: <a href="http://www.unicode.org/charts/PDF/UFB00.pdf">http://www.unicode.org/charts/PDF/UFB00.pdf</a></description></item>
///   <item><description>Halfwidth and Fullwidth Forms: <a href="http://www.unicode.org/charts/PDF/UFF00.pdf">http://www.unicode.org/charts/PDF/UFF00.pdf</a></description></item>
/// </ul>
/// <para/>
/// See: <a href="http://en.wikipedia.org/wiki/Latin_characters_in_Unicode">http://en.wikipedia.org/wiki/Latin_characters_in_Unicode</a>
/// <para/>
/// For example, '&amp;agrave;' will be replaced by 'a'.
/// </summary>
public static partial class StringExtensions
{
    /// <summary>
    /// Converts characters above ASCII to their ASCII equivalents.  For example,
    /// accents are removed from accented characters. 
    /// </summary>
    /// <param name="input">     The string of characters to fold </param>
    /// <param name="length">    The length of the folded return string </param>
    /// <returns> length of output </returns>
    public static string FoldToASCII(this string input, int? length = null)
    {
        // See https://gist.github.com/andyraddatz/e6a396fb91856174d4e3f1bf2e10951c
    }
}

다른 사람을 돕는 희망, 이것이 내가 찾은 가장 강력한 솔루션입니다!


주의 사항 : 1) 개념은 로케일에 따라 다릅니다. 예를 들어 "ä"는 "a"또는 "aa"일 수 있습니다. 2) 이름이 잘못되었거나 잘못 설명 됨 : 결과는 반드시 C0 Controls 및 Basic Latin 블록에서만 발생하는 것은 아닙니다. 라틴 문자 및 일부 기호 변형 만 "동등한 항목"으로 변환합니다. (물론, 나중에 비 C0 Controls 및 Basic Latin 블록 문자를 바꾸거나 제거하기 위해 다른 단계를 거쳐야 할 수도 있습니다.) 그러나 이것은 잘 작동합니다.
Tom Blodget

2

이것은 VB 버전입니다 (GREEK와 함께 작동).

System.Text를 가져옵니다.

System.Globalization을 가져옵니다.

Public Function RemoveDiacritics(ByVal s As String)
    Dim normalizedString As String
    Dim stringBuilder As New StringBuilder
    normalizedString = s.Normalize(NormalizationForm.FormD)
    Dim i As Integer
    Dim c As Char
    For i = 0 To normalizedString.Length - 1
        c = normalizedString(i)
        If CharUnicodeInfo.GetUnicodeCategory(c) <> UnicodeCategory.NonSpacingMark Then
            stringBuilder.Append(c)
        End If
    Next
    Return stringBuilder.ToString()
End Function

1
오래된 대답 일지 모르지만 왜 변수 선언과 첫 번째 할당에 별도의 줄을 사용합니까?
NiKiZe

2

HelperSharp package를 사용해보십시오 .

RemoveAccents 메소드가 있습니다.

 public static string RemoveAccents(this string source)
 {
     //8 bit characters 
     byte[] b = Encoding.GetEncoding(1251).GetBytes(source);

     // 7 bit characters
     string t = Encoding.ASCII.GetString(b);
     Regex re = new Regex("[^a-zA-Z0-9]=-_/");
     string c = re.Replace(t, " ");
     return c;
 }

2

이것이 내 모든 .NET 프로그램에서 분음 부호 문자를 분음 부호가 아닌 문자로 바꾸는 방법입니다.

씨#:

//Transforms the culture of a letter to its equivalent representation in the 0-127 ascii table, such as the letter 'é' is substituted by an 'e'
public string RemoveDiacritics(string s)
{
    string normalizedString = null;
    StringBuilder stringBuilder = new StringBuilder();
    normalizedString = s.Normalize(NormalizationForm.FormD);
    int i = 0;
    char c = '\0';

    for (i = 0; i <= normalizedString.Length - 1; i++)
    {
        c = normalizedString[i];
        if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
        {
            stringBuilder.Append(c);
        }
    }

    return stringBuilder.ToString().ToLower();
}

VB .NET :

'Transforms the culture of a letter to its equivalent representation in the 0-127 ascii table, such as the letter "é" is substituted by an "e"'
Public Function RemoveDiacritics(ByVal s As String) As String
    Dim normalizedString As String
    Dim stringBuilder As New StringBuilder
    normalizedString = s.Normalize(NormalizationForm.FormD)
    Dim i As Integer
    Dim c As Char

    For i = 0 To normalizedString.Length - 1
        c = normalizedString(i)
        If CharUnicodeInfo.GetUnicodeCategory(c) <> UnicodeCategory.NonSpacingMark Then
            stringBuilder.Append(c)
        End If
    Next
    Return stringBuilder.ToString().ToLower()
End Function



1
Imports System.Text
Imports System.Globalization

 Public Function DECODE(ByVal x As String) As String
        Dim sb As New StringBuilder
        For Each c As Char In x.Normalize(NormalizationForm.FormD).Where(Function(a) CharUnicodeInfo.GetUnicodeCategory(a) <> UnicodeCategory.NonSpacingMark)  
            sb.Append(c)
        Next
        Return sb.ToString()
    End Function

NFC 대신 NFD를 사용하면 요청 된 것보다 훨씬 많은 변경이 발생할 수 있습니다.
Jon Hanna

1

이 사람의 말 :

Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(text));

실제로 å는 하나의 문자 (같은 문자를 나타내는 수정자가 아닌 문자 코드 00E5인) 와 같은 수정자를 플러스의 일종의 수정 자로 나누고 ASCII 변환은 수정자를 제거하고 유일한 수정자를 남겨 둡니다 . 0061030Aaa


1

나는 azrafe7에서 제공하는 간결하고 기능적인 코드를 정말 좋아합니다 . 그래서 확장 방법으로 변환하기 위해 조금 변경했습니다.

public static class StringExtensions
{
    public static string RemoveDiacritics(this string text)
    {
        const string SINGLEBYTE_LATIN_ASCII_ENCODING = "ISO-8859-8";

        if (string.IsNullOrEmpty(text))
        {
            return string.Empty;
        }

        return Encoding.ASCII.GetString(
            Encoding.GetEncoding(SINGLEBYTE_LATIN_ASCII_ENCODING).GetBytes(text));
    }
}

이것은 모든 광택 분음 부호와 함께 작동하는 유일한 방법입니다. 허용 된 답변은 Ł 및 ł 문자로 작동하지 않습니다.
yarecky

-3

평판이 충분하지 않으면 Alexander의 훌륭한 링크에 대해서는 언급 할 수 없습니다. -Lucene은 합리적인 경우에 효과가있는 유일한 솔루션 인 것으로 보입니다.

간단한 복사-붙여 넣기 솔루션을 원하는 사람들을 위해 Lucene의 코드를 활용합니다.

문자열 테스트 베드 = "ÁÂÄÅÇÉÍÎÓÖØÚÜÞàáâãäåæçèéêëìíîïðñóôöøúüāăčĐęğıŁłńŌōřŞşšźžșțệủ";

Console.WriteLine (Lucene.latinizeLucene (testbed));

AAAACEIIOOOUUTHaaaaaaaeceeeeiiiidnoooouuaacDegiLlnOorSsszzsteu

//////////

public static class Lucene
{
    // source: https://raw.githubusercontent.com/apache/lucenenet/master/src/Lucene.Net.Analysis.Common/Analysis/Miscellaneous/ASCIIFoldingFilter.cs
    // idea: /programming/249087/how-do-i-remove-diacritics-accents-from-a-string-in-net (scroll down, search for lucene by Alexander)
    public static string latinizeLucene(string arg)
    {
        char[] argChar = arg.ToCharArray();

        // latinizeLuceneImpl can expand one char up to four chars - e.g. Þ to TH, or æ to ae, or in fact ⑽ to (10)
        char[] resultChar = new String(' ', arg.Length * 4).ToCharArray();

        int outputPos = Lucene.latinizeLuceneImpl(argChar, 0, ref resultChar, 0, arg.Length);

        string ret = new string(resultChar);
        ret = ret.Substring(0, outputPos);

        return ret;
    }

    /// <summary>
    /// Converts characters above ASCII to their ASCII equivalents.  For example,
    /// accents are removed from accented characters. 
    /// <para/>
    /// @lucene.internal
    /// </summary>
    /// <param name="input">     The characters to fold </param>
    /// <param name="inputPos">  Index of the first character to fold </param>
    /// <param name="output">    The result of the folding. Should be of size >= <c>length * 4</c>. </param>
    /// <param name="outputPos"> Index of output where to put the result of the folding </param>
    /// <param name="length">    The number of characters to fold </param>
    /// <returns> length of output </returns>
    private static int latinizeLuceneImpl(char[] input, int inputPos, ref char[] output, int outputPos, int length)
    {
        int end = inputPos + length;
        for (int pos = inputPos; pos < end; ++pos)
        {
            char c = input[pos];

            // Quick test: if it's not in range then just keep current character
            if (c < '\u0080')
            {
                output[outputPos++] = c;
            }
            else
            {
                switch (c)
                {
                    case '\u00C0': // À  [LATIN CAPITAL LETTER A WITH GRAVE]
                    case '\u00C1': // Á  [LATIN CAPITAL LETTER A WITH ACUTE]
                    case '\u00C2': // Â  [LATIN CAPITAL LETTER A WITH CIRCUMFLEX]
                    case '\u00C3': // Ã  [LATIN CAPITAL LETTER A WITH TILDE]
                    case '\u00C4': // Ä  [LATIN CAPITAL LETTER A WITH DIAERESIS]
                    case '\u00C5': // Å  [LATIN CAPITAL LETTER A WITH RING ABOVE]
                    case '\u0100': // Ā  [LATIN CAPITAL LETTER A WITH MACRON]
                    case '\u0102': // Ă  [LATIN CAPITAL LETTER A WITH BREVE]
                    case '\u0104': // Ą  [LATIN CAPITAL LETTER A WITH OGONEK]
                    case '\u018F': // Ə  http://en.wikipedia.org/wiki/Schwa  [LATIN CAPITAL LETTER SCHWA]
                    case '\u01CD': // Ǎ  [LATIN CAPITAL LETTER A WITH CARON]
                    case '\u01DE': // Ǟ  [LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON]
                    case '\u01E0': // Ǡ  [LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON]
                    case '\u01FA': // Ǻ  [LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE]
                    case '\u0200': // Ȁ  [LATIN CAPITAL LETTER A WITH DOUBLE GRAVE]
                    case '\u0202': // Ȃ  [LATIN CAPITAL LETTER A WITH INVERTED BREVE]
                    case '\u0226': // Ȧ  [LATIN CAPITAL LETTER A WITH DOT ABOVE]
                    case '\u023A': // Ⱥ  [LATIN CAPITAL LETTER A WITH STROKE]
                    case '\u1D00': // ᴀ  [LATIN LETTER SMALL CAPITAL A]
                    case '\u1E00': // Ḁ  [LATIN CAPITAL LETTER A WITH RING BELOW]
                    case '\u1EA0': // Ạ  [LATIN CAPITAL LETTER A WITH DOT BELOW]
                    case '\u1EA2': // Ả  [LATIN CAPITAL LETTER A WITH HOOK ABOVE]
                    case '\u1EA4': // Ấ  [LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE]
                    case '\u1EA6': // Ầ  [LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE]
                    case '\u1EA8': // Ẩ  [LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE]
                    case '\u1EAA': // Ẫ  [LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE]
                    case '\u1EAC': // Ậ  [LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW]
                    case '\u1EAE': // Ắ  [LATIN CAPITAL LETTER A WITH BREVE AND ACUTE]
                    case '\u1EB0': // Ằ  [LATIN CAPITAL LETTER A WITH BREVE AND GRAVE]
                    case '\u1EB2': // Ẳ  [LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE]
                    case '\u1EB4': // Ẵ  [LATIN CAPITAL LETTER A WITH BREVE AND TILDE]
                    case '\u1EB6': // Ặ  [LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW]
                    case '\u24B6': // Ⓐ  [CIRCLED LATIN CAPITAL LETTER A]
                    case '\uFF21': // A  [FULLWIDTH LATIN CAPITAL LETTER A]
                        output[outputPos++] = 'A';
                        break;
                    case '\u00E0': // à  [LATIN SMALL LETTER A WITH GRAVE]
                    case '\u00E1': // á  [LATIN SMALL LETTER A WITH ACUTE]
                    case '\u00E2': // â  [LATIN SMALL LETTER A WITH CIRCUMFLEX]
                    case '\u00E3': // ã  [LATIN SMALL LETTER A WITH TILDE]
                    case '\u00E4': // ä  [LATIN SMALL LETTER A WITH DIAERESIS]
                    case '\u00E5': // å  [LATIN SMALL LETTER A WITH RING ABOVE]
                    case '\u0101': // ā  [LATIN SMALL LETTER A WITH MACRON]
                    case '\u0103': // ă  [LATIN SMALL LETTER A WITH BREVE]
                    case '\u0105': // ą  [LATIN SMALL LETTER A WITH OGONEK]
                    case '\u01CE': // ǎ  [LATIN SMALL LETTER A WITH CARON]
                    case '\u01DF': // ǟ  [LATIN SMALL LETTER A WITH DIAERESIS AND MACRON]
                    case '\u01E1': // ǡ  [LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON]
                    case '\u01FB': // ǻ  [LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE]
                    case '\u0201': // ȁ  [LATIN SMALL LETTER A WITH DOUBLE GRAVE]
                    case '\u0203': // ȃ  [LATIN SMALL LETTER A WITH INVERTED BREVE]
                    case '\u0227': // ȧ  [LATIN SMALL LETTER A WITH DOT ABOVE]
                    case '\u0250': // ɐ  [LATIN SMALL LETTER TURNED A]
                    case '\u0259': // ə  [LATIN SMALL LETTER SCHWA]
                    case '\u025A': // ɚ  [LATIN SMALL LETTER SCHWA WITH HOOK]
                    case '\u1D8F': // ᶏ  [LATIN SMALL LETTER A WITH RETROFLEX HOOK]
                    case '\u1D95': // ᶕ  [LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK]
                    case '\u1E01': // ạ  [LATIN SMALL LETTER A WITH RING BELOW]
                    case '\u1E9A': // ả  [LATIN SMALL LETTER A WITH RIGHT HALF RING]
                    case '\u1EA1': // ạ  [LATIN SMALL LETTER A WITH DOT BELOW]
                    case '\u1EA3': // ả  [LATIN SMALL LETTER A WITH HOOK ABOVE]
                    case '\u1EA5': // ấ  [LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE]
                    case '\u1EA7': // ầ  [LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE]
                    case '\u1EA9': // ẩ  [LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE]
                    case '\u1EAB': // ẫ  [LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE]
                    case '\u1EAD': // ậ  [LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW]
                    case '\u1EAF': // ắ  [LATIN SMALL LETTER A WITH BREVE AND ACUTE]
                    case '\u1EB1': // ằ  [LATIN SMALL LETTER A WITH BREVE AND GRAVE]
                    case '\u1EB3': // ẳ  [LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE]
                    case '\u1EB5': // ẵ  [LATIN SMALL LETTER A WITH BREVE AND TILDE]
                    case '\u1EB7': // ặ  [LATIN SMALL LETTER A WITH BREVE AND DOT BELOW]
                    case '\u2090': // ₐ  [LATIN SUBSCRIPT SMALL LETTER A]
                    case '\u2094': // ₔ  [LATIN SUBSCRIPT SMALL LETTER SCHWA]
                    case '\u24D0': // ⓐ  [CIRCLED LATIN SMALL LETTER A]
                    case '\u2C65': // ⱥ  [LATIN SMALL LETTER A WITH STROKE]
                    case '\u2C6F': // Ɐ  [LATIN CAPITAL LETTER TURNED A]
                    case '\uFF41': // a  [FULLWIDTH LATIN SMALL LETTER A]
                        output[outputPos++] = 'a';
                        break;
                    case '\uA732': // Ꜳ  [LATIN CAPITAL LETTER AA]
                        output[outputPos++] = 'A';
                        output[outputPos++] = 'A';
                        break;
                    case '\u00C6': // Æ  [LATIN CAPITAL LETTER AE]
                    case '\u01E2': // Ǣ  [LATIN CAPITAL LETTER AE WITH MACRON]
                    case '\u01FC': // Ǽ  [LATIN CAPITAL LETTER AE WITH ACUTE]
                    case '\u1D01': // ᴁ  [LATIN LETTER SMALL CAPITAL AE]
                        output[outputPos++] = 'A';
                        output[outputPos++] = 'E';
                        break;
                    case '\uA734': // Ꜵ  [LATIN CAPITAL LETTER AO]
                        output[outputPos++] = 'A';
                        output[outputPos++] = 'O';
                        break;
                    case '\uA736': // Ꜷ  [LATIN CAPITAL LETTER AU]
                        output[outputPos++] = 'A';
                        output[outputPos++] = 'U';
                        break;

        // etc. etc. etc.
        // see link above for complete source code
        // 
        // unfortunately, postings are limited, as in
        // "Body is limited to 30000 characters; you entered 136098."

                    [...]

                    case '\u2053': // ⁓  [SWUNG DASH]
                    case '\uFF5E': // ~  [FULLWIDTH TILDE]
                        output[outputPos++] = '~';
                        break;
                    default:
                        output[outputPos++] = c;
                        break;
                }
            }
        }
        return outputPos;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.