我正在尝试转换一些法语加拿大语的字符串,基本上,我希望能够在保留字母的同时取出字母中的法语重音符号.(例如转换é
为e
,所以crème brûlée
会变成creme brulee
)
实现这一目标的最佳方法是什么?
我没有使用过这种方法,但迈克尔·卡普兰在他的博客文章(带有令人困惑的标题)中描述了这样做的方法,该文章讨论剥离变音符号:剥离是一项有趣的工作(又名无意义的意思,又名所有Mn字符)是非间距的,但有些比其他的更不间距)
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中的重音符号和波形符号中使用简单的基于表格的方法.
这对我有用...
string accentedStr; byte[] tempBytes; tempBytes = System.Text.Encoding.GetEncoding("ISO-8859-8").GetBytes(accentedStr); string asciiStr = System.Text.Encoding.UTF8.GetString(tempBytes);
快速和短暂!
如果有人感兴趣,我正在寻找类似的东西并结束了以下内容:
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 }
我需要一些可以转换所有主要unicode字符的东西,并且投票的答案留了一些,所以我在convert_accented_characters($str)
C#中创建了一个可以轻松定制的CodeIgniter版本:
using System; using System.Text; using System.Collections.Generic; public static class Strings { static Dictionaryforeign_characters = new Dictionary { { "äæ?", "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" }, { "ÒÓÔÕ?????Ø??????????????????", "O" }, { "òóôõ?????ø?º?????????????????", "o" }, { "?", "P" }, { "?", "p" }, { "?????", "R" }, { "?????", "r" }, { "????Š??", "S" }, { "????š????", "s" }, { "??????", "T" }, { "?????", "t" }, { "ÙÚÛ?????????????????????", "U" }, { "ùúû???????????????????????", "u" }, { "ÝŸ?????????", "Y" }, { "ýÿ??????", "y" }, { "?", "V" }, { "?", "v" }, { "?", "W" }, { "?", "w" }, { "??Ž??", "Z" }, { "??ž??", "z" }, { "Æ?", "AE" }, { "ß", "ss" }, { "?", "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 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 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
如果有人感兴趣,这里是java等价物:
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.charAt(i)使用StringBuilder.你在这里隐藏了O(n²)运行时.
这里的这个和其他Java答案只是弄乱了这个线程。问题是关于c#(.NET)而不是Java!
6> realbart..:我经常使用基于我在这里找到的另一个版本的扩展方法(请参阅替换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); } }
7> Sergio Cabra..:希腊语(ISO)的CodePage 可以做到这一点
有关此代码页的信息是
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)
因为first是名称,第二个是Encoding的代码页.
太精彩了!简短而有效!
8> EricBDev..:有趣的是,这样一个问题可以得到这么多答案,但又没有一个适合我的要求:)周围有太多语言,一种完全与语言无关的解决方案真的不可能AFAIK,因为其他人提到FormC或FormD正在发出问题。
由于原始问题与法语有关,因此最简单的工作答案确实是
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(); }它可能无法提供最佳性能,但至少它很容易阅读和扩展。正则表达式是行不通的,比任何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); }