MS_CharacterValidation - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki
- æ»ãïŒæåã³ãŒãïŒ
æåãã§ãã¯ã¯ãæååãçãäºåã«é²ãããã«è¡ãããã
以äžã®æåãã§ãã¯ã»ã«ãŒãã³ãäžè¬çã§ããã
è£è¶³ïŒ3 ã€ã®æ¹åŒã®äœçœ®ä»ãïŒ: æ¬ããŒãžã¯
ç¯å²ãã§ã㯠/ åå¥ãã§ã㯠/ å¯éãã§ãã¯ã® 3 ã€ãæ±ãã
ããããåŸæãªå Žé¢ãéãã®ã§ãå ã«æŽçããŠããã
æ¹åŒ ä»çµã¿ åãå Žé¢ åŒ±ç¹ ç¯å²ãã§ã㯠ã³ãŒãå€ã®ç¯å²ã§å€å® é£ç¶ããé åïŒJIS 第1第2æ°Žæºãå€åé åïŒ é£ã³å°ã«ã¯äœ¿ããªã åå¥ãã§ã㯠æåã®äžèЧãšçªãåãã é£ã³å°ã®æåïŒJIS2004 è¿œå æåïŒ äžèЧã®ä¿å®ãèŠã å¯éãã§ã㯠åŸåŸ©å€æããŠäžèŽãèŠã ããã®æåã³ãŒãã§éãããã å®è£ äŸåãé ã æãå®åçãªã®ã¯å¯éãã§ãã¯ã§ããã
ãçžæã·ã¹ãã ã«éãããããçŽæ¥ç¢ºãããããã
æå衚ã®ç¥èãèŠããªããæ¬ããŒãžã®æåŸã§æ±ãããŠããã
ãšã³ã³ãŒãåŸã«ãç¯å²ãã§ãã¯ãããã
JIS 第1第2æ°ŽæºæŒ¢åããã§ãã¯ãã
ã·ãã JIS ã®ã³ãŒãç¯å²ã§ãã§ãã¯ãè¡ãå¿
èŠãããã®ã§ã
äžæåã¥ã€ã·ãã JIS ã«ãšã³ã³ãŒããæ°å€åã«å€æãç¯å²ãã§ãã¯ãè¡ãã
- JISX0208_1983Checker
https://github.com/OpenTouryoProject/OpenTouryo/blob/develop/root/programs/CS/Frameworks/Infrastructure/Business/Str/JISX0208_1983Checker.cs
//**********************************************************************************
//* All Rights Reserved, Copyright (C) 2007,2012 Hitachi Solutions,Ltd.
//**********************************************************************************
//**********************************************************************************
//* ã¯ã©ã¹å ïŒJISX0208_1983Checker
//* ã¯ã©ã¹æ¥æ¬èªå ïŒJIS X 0208-1983æåã³ãŒãç¯å²ãã§ãã¯ã»ã¯ã©ã¹
//* ãããããããããã»01ïœ08åºïŒèšå·ãè±æ°åãããª
//* ãããããããããã»16ïœ47åºïŒJIS第1æ°ŽæºæŒ¢å
//* ãããããããããã»48ïœ84åºïŒJIS第2æ°ŽæºæŒ¢å
//* ããããããããâ»JIS X 0208-1990ã§è¿œå ããããå[7425]ããç[7426]ãã¯å«ãŸããªã
//* ãããããããããâ»NECæ©çš®äŸåæåãNECã®IBMæ¡åŒµæåãIBMæ¡åŒµæåã¯å«ãŸããªãè£è¶³ïŒåºç¹ãš Shift_JIS ã®å¯Ÿå¿ïŒ: ã³ã¡ã³ãã®ãåºãã¯
åºç¹ã³ãŒãã§ããããã®ãŸãŸã§ã¯ Shift_JIS ã®ãã€ãå€ã§ã¯ãªãã
åæããã·ãã JIS ã«ãšã³ã³ãŒããæ°å€åã«å€æãããšæžããŠããã®ã¯ã
åºç¹ã§ã¯ãªã Shift_JIS ã® 2 ãã€ãå€ã§å€å®ãããšããæå³ã§ããããShift_JIS ã® 2 ãã€ãæåã®æ§é ã 1 ãã€ãç®ïŒ 0x81ïœ0x9Fã0xE0ïœ0xEFïŒJIS X 0208 ã®ç¯å²ïŒ 0xF0ïœ0xFCïŒå€åé åïŒ 0xFAïœ0xFCïŒIBM æ¡åŒµæåïŒ 2 ãã€ãç®ïŒ 0x40ïœ0x7Eã0x80ïœ0xFC1 ãã€ãç®ãš 2 ãã€ãç®ã®ç¯å²ãéãªã£ãŠããããã
ãã€ãåäœã§èµ°æ»ãããšèª€å€å®ããïŒããããã5C åé¡ãïŒãã衚ãïŒ 0x95 0x5C â 2 ãã€ãç®ã 0x5CïŒïŒ ASCII ã® "\"ïŒ â ãã€ãåãçŽ æŽã«æ±ããšããã¹åºåãããšã¹ã±ãŒããšèª€èªããã â ããœã(0x83 0x5C)ããåã(0x8F 0x5C) çãåæ§åæããäžæåã¥ã€ããšåŒ·èª¿ããŠããã®ã¯ããã®åé¡ãé¿ããããã§ããã
éèŠãªææã§ããã
çŸåšã® .NET ã§ã¯stringã UTF-16 ãªã®ã§ã
foreach (char c in s)ã§èªç¶ã«æååäœã«ãªããã
byte[]ã«èœãšããŠããèµ°æ»ãããšåãçœ ã«ã¯ãŸãããªãããã®å€å®ã¯çŸåšã§ã¯ãæåéåã®çµã蟌ã¿ããšããŠäœ¿ãããã
ç®çã¯æååã鲿¢ã§ã¯ãªããã»ã¬ã¬ã·ãŒ ã·ã¹ãã ïŒCP932 åæïŒãžé£æºããéã®å ¥åå¶é ã»åž³ç¥šã®å€åãã©ã³ãã«ååšããæåã ãã«éå®ãã ã»æ°åæ¬ã§ãç»é²å¯èœãªæåããæ¥åã«ãŒã«ãšããŠå®ãããšãã£ãæ¥åèŠä»¶ã®å®è£ ã§ããã
çŽç²ãªæååã察çãšããŠã¯ãUTF-8 ã§éãæ¹ãæ ¹æ¬çã§ãã
ïŒã¢ããªã±ãŒã·ã§ã³ã®UnicodeåïŒã
Unicode ã®å€åç¯å²ããã§ãã¯ããã
- BMP é å U+E000âU+F8FF (6,400å)
- 15é¢ U+F0000âU+FFFFD (65,534å)
- 16é¢ U+100000âU+10FFFD (65,534å)
- äœè«ïŒã·ãã JIS ã®å€åç¯å²ïŒU+E000ïœU+E757ïŒ0xF040ïœ0xF9FCïŒã
- äžæåã¥ã€ Unicode æ°å€ã«å€æãç¯å²ãã§ãã¯ãè¡ãã
- Javaã.NET ã®æåå㯠Unicode ã®ãã Unicode ã®ç¯å²ãã§ãã¯ã¯ã
以äžã®æ§ãªã³ãŒãã§ç°¡åã«ãã§ãã¯ã§ããã
ïŒUnicodeïŒ JIS X 0221ïŒ ååœã®å·¥æ¥èŠæ Œã§äœ¿çšããããïŒïŒ
string from = "æååãåæåããã"
StringBuilder to = new StringBuilder();
foreach (char c in from)
{
int charCode = (int)c;
if (57344 <= charCode && charCode <= 63743)
{
// Unicodeã®å€åç¯å²
// BMPé å U+E000âU+F8FF (6,400å)
}
else if (983040 <= charCode && charCode <= 1048573)
{
// Unicodeã®å€åç¯å²
// 15é¢ U+F0000âU+FFFFD (65,534å)
}
else if (1048576 <= charCode && charCode <= 1114109)
{
// Unicodeã®å€åç¯å²
// 16é¢ U+100000âU+10FFFD (65,534å)
}
else
{
// Unicodeã®å€åã§ãªãã
}
}ç§»è¡ã¡ã¢ïŒãã®ãµã³ãã«ã¯ 15 é¢ã»16 é¢ãæ€åºã§ããªãïŒ: 仿§ã¯
æ£ããããå®è£ ããã®ä»æ§ãæºãããŠããªãããåé¡ã C# ã® char ã¯ã16 ãããïŒUTF-16 ã® 1 åäœïŒãã§ãã â (int)c ã®æå€§å€ã¯ 65535 â 983040ïŒU+F0000ïŒä»¥äžã®æ¡ä»¶ã¯ãçµ¶å¯Ÿã«æç«ããªãã 15 é¢ã»16 é¢ã®æåã¯ããµãã²ãŒã ãã¢ãã§è¡šçŸãããããã char 1 ã€ãã€èŠãŠããŠã¯æ€åºã§ããªã â U+F0000 㯠char 2 ã€ïŒ0xDB80, 0xDC00ïŒã«åãããŠããæ¬ããŒãžã®åŸåã§ãµãã²ãŒã ãã¢ã®è©±ãå¥é ç®ãšããŠåºãŠãããã
ãã® 2 ã€ã¯åãåé¡ã§ããã
ãµãã²ãŒã ãã¢ãèæ ®ããèµ°æ»ãå¿ èŠã§ãããä¿®æ£çïŒ
charã§ã¯ãªãã³ãŒããã€ã³ãã§èµ°æ»ããïŒ:// .NET Core 3.0 以éïŒRune ãã³ãŒããã€ã³ãã衚ã foreach (Rune r in from.EnumerateRunes()) { int cp = r.Value; // â 0x10FFFF ãŸã§æ£ããå ¥ã if (0xE000 <= cp && cp <= 0xF8FF) // BMP ã®ç§çšé å { /* å€å */ } else if (0xF0000 <= cp && cp <= 0xFFFFD) // 15 é¢ïŒè£å©ç§çšé å AïŒ { /* å€å */ } else if (0x100000 <= cp && cp <= 0x10FFFD) // 16 é¢ïŒè£å©ç§çšé å BïŒ { /* å€å */ } else { /* å€åã§ãªã */ } }
Runeã䜿ããªãç°å¢ïŒ.NET FrameworkïŒã§ã¯ã
char.ConvertToUtf32ã䜿ããfor (int i = 0; i < from.Length; i++) { int cp; if (char.IsHighSurrogate(from[i]) && i + 1 < from.Length && char.IsLowSurrogate(from[i + 1])) { cp = char.ConvertToUtf32(from[i], from[i + 1]); i++; // â ãã¢ãªã®ã§ 2 ã€é²ãã } else { cp = from[i]; } // cp ã§å€å®ãã }
Runeã䜿ãã°ããã®å®ååŠçãæžããã«æžãã
.NET Core 3.0 以éãªãRuneã第äžéžæã§ããã
è£è¶³ïŒç§çšé åã®æ§è³ªïŒ: 仿§ã«æãããã 3 ã€ã®é åã¯ã
Unicode ã§ã¯ **PUAïŒPrivate Use Areaãç§çšé åïŒ**ãšåŒã°ããã
é å åç§° åæ° U+E000ïœU+F8FF ç§çšé åïŒBMP å ïŒ 6,400 U+F0000ïœU+FFFFD è£å©ç§çšé å AïŒ15 é¢ïŒ 65,534 U+100000ïœU+10FFFD è£å©ç§çšé å BïŒ16 é¢ïŒ 65,534 **ãç§çšãã®æå³ã¯ãUnicode ã¯äœãå®çŸ©ããªãã**ã§ããã
ã»ã©ã®æåãå²ãåœãŠããã¯ã䜿ãåŽã®åæã ã»ãããã£ãŠãçµç¹ããŸãããšæå³ãå€ããã â å€åãåããæ ¹æ¬åå ïŒ[Windowsã®å€å] åç §ïŒ ã»ãã©ã³ãããªããã° â¡ ãè±è ã§è¡šç€ºãããåæããã·ãã JIS ã®å€åç¯å²ïŒU+E000ïœU+E757ããšæžããŠããã®ã¯ã
CP932 ã®å€åé åïŒ0xF040ïœ0xF9FCã1,880 åïŒã
Unicode ã®ç§çšé åã®å é ã«é ã«å¯Ÿå¿ä»ããããŠããããã§ããã
ãã㯠Microsoft ãããæ±ºããã ãã®å¯Ÿå¿ã§ããã
ä»ç€Ÿã®å€æè¡šã§ã¯å¥ã®å€ã«ãªãåŸããçŸåšã®æé:
ã»æ°èŠã·ã¹ãã ã§ãç§çšé åã䜿ããªãã ã»æ¢åã®å€åã¯ãIVSïŒç°äœåã»ã¬ã¯ã¿ïŒã Unicode ã®æ£èŠã®æåãžç§»è¡ã â [Windowsã®å€å] ãåç § ã»ã©ãããŠãæ®ããªãããå€æè¡šãæç€ºçã«ç®¡çããã
ã³ãŒã衚ã§é£ç¶ããªãæåããã§ãã¯ããã
JIS2004ãã§ãã¯
- 仿§ïŒ
JIS2004 ã§è¿œå ãããæåããã§ãã¯ããã - å®è£
ïŒ
Unicode ã®ã¿ã«ååšããã³ãŒãç¯å²ããã©ãã©ãªã®ã§ã
JIS2004 è¿œå æåé åãåæåããäžæåã¥ã€ãæ¯èŒåŠçãè¡ãã
-
仿§ïŒ
JIS2004 ã§è¿œå ããããµãã²ãŒããã¢æåããã§ãã¯ããã -
å®è£ ïŒ
-
Regex.IsMatch() ã¡ãœãããchar.IsSurrogate() ã¡ãœããã䜿çšããã
-
Regex.IsMatch() ã¡ãœããïŒæ£èŠè¡šçŸïŒã䜿çšããã
-
以äžãµã³ãã«ã»ã³ãŒãã
//ããã«å€å®ããæååãå ¥ããã string strSurrogatesPair = textBox1.Text; Regex rg = new Regex("^[^\uD800-\uDBFF\uDC00-\uDFFF]+$"); //ãµãã²ãŒã ãã¢æåãæååäžã«å«ãŸããŠããã //Regex.IsMatch() ã¡ãœããå€å® if ( rg.IsMatch( strSurrogatesPair ) ) { // ãµãã²ãŒããã¢æåãå«ãŸããŠããªãã } else { // ãµãã²ãŒããã¢æåãå«ãŸããŠããã } // çµåæåã¯ãã§ãã¯ã§ããªãã
-
-
char.IsSurrogate() ã¡ãœããã䜿çšããã
-
以äžãµã³ãã«ã»ã³ãŒãã
//ããã«å€å®ããæååãå ¥ããã string strSurrogatesPair = textBox1.Text; //ãµãã²ãŒã ãã¢æåãæååäžã«å«ãŸããŠããã //char.IsSurrogate()ã¡ãœããã§å€å® int i = 1; foreach (char ch in strSurrogatesPair.ToCharArray()) { if(char.IsSurrogate(ch)) { MessageBox.Show(i.ToString() + "æåç®ã«ãµãã²ãŒã ãã¢æåãå«ãŸããŠããŸã"); return; } else { i++; } } MessageBox.Show("ãµãã²ãŒã ãã¢æåãå«ãŸããŠããŸãã");
-
ãµãã²ãŒã ãã¢æåãåé€ãããµã³ãã« ã³ãŒã
//ããã«å€å®ããæååãå ¥ããã string strSurrogatesPair = textBox1.Text; StringBuilder sb = new StringBuilder(); //ãµãã²ãŒã ãã¢ãæååäžã«å«ãŸããŠããã //char.IsSurrogate()ã¡ãœããã§å€å® foreach (char ch in strSurrogatesPair.ToCharArray()) { if (char.IsSurrogate(ch)) { // ç Žæ£ } else { sb.Append(ch); } } textBox1.Text = sb.ToString();
-
-
â»ãåè
ã¯ãååšãã§ãã¯ã®ã¿ã
ããåŸè
ã¯ãæåã®äœçœ®ãŸã§ç¹å®å¯èœïŒâŽåé€ãå¯èœãïŒã
â»ããŸããäžèšã®æ¹æ³ã§ã¯ãçµåæåã¯ãã§ãã¯ã§ããªãã
è£è¶³ïŒãµã³ãã«ã®æ³šæç¹ïŒ: ã©ã¡ããåããã
现éšã«æ³šæãã¹ãç¹ããããâ æ£èŠè¡šçŸçã¯ã空æååãã§çµæãå転ãã
// "^[^...]+$" 㯠1 æå以äžãèŠæ±ãã rg.IsMatch(""); // false â ãå«ãŸããŠããããšèª€å€å®ããã
+ã*ã«ãããã空æååãå ã«åŒŸããâ¡
char.IsSurrogateçã¯ãæåç®ãã®æ°ãæ¹ãå®éãšããã"ãð ®·ã" ãèµ°æ»ãããš index 0: 'ã' â i = 2 index 1: 0xD842ïŒäžäœïŒâ ããã§ã2 æåç®ããšå ±å å®éã®èŠãç®ã¯ã2 æåç®ãã§åã£ãŠãããã ãµãã²ãŒãããåã«ãµãã²ãŒãããããšã以éã 2 ãã€ãããèŠãç®ã®äœçœ®ãåºããããªã
StringInfoã䜿ãïŒåŸè¿°ïŒã⢠åé€ãµã³ãã«ã¯ãå£ããæååããäœãåŸã
char.IsSurrogateã¯äžäœã»äžäœã®äž¡æ¹ã« true ãè¿ãããã
ãã¢ã®äž¡æ¹ãæ¶ããããã®ç¹ã¯æ£ããã
ãã ãå€ç«ãµãã²ãŒãïŒãã¢ã®çå²ãã ãïŒãå ¥åã«ãã£ãå Žåã
é»ã£ãŠæ¶ãããããäžæ£ãªå ¥åãæ€åºã§ããªããçŸåšã®æžãæ¹:
// ãµãã²ãŒã ãã¢ïŒBMP å€ã®æåïŒãå«ãã bool hasNonBmp = str.EnumerateRunes().Any(r => !r.IsBmp); // BMP å€ã®æåãé€å»ãã string removed = string.Concat( str.EnumerateRunes().Where(r => r.IsBmp).Select(r => r.ToString()));
Runeã¯äžæ£ãªãµãã²ãŒããU+FFFDïŒçœ®ææåïŒãšããŠè¿ãããã
å£ããå ¥åãæ€åºã§ããå©ç¹ãããã
- çŸç¶ãããããªããæ¹æ³ãç¡ãã
-
ãµãã²ãŒããã¢ãçµåæåãå«ãŸããŠããã調ã¹ã .NET Tips C#, VB.NET
https://dobon.net/vb/dotnet/string/issurrogatepair.html#section4\ çµåæåãå«ãŸããŠããã調ã¹ããã ããMarks ã«ããŽãªã«ãã¹ãŠã®çµåæåãå«ãŸããŠãããã
ãããŠãçµåæå以å€ã®æåãäžåå«ãŸããŠããªããã«ã€ããŠã¯ãã¯ã£ããããŠããŸããã
-
è£è¶³ïŒçŸåšã¯
StringInfo/TextElementEnumeratorã§æ±ããïŒ: åæã®
ãããããªããæ¹æ³ãç¡ãããšããç¶æ³ã¯ãçŸåšã¯æ¹åããŠããã.NET 5 以éã
StringInfo㯠Unicode ã®
æžèšçŽ ã¯ã©ã¹ã¿ïŒGrapheme ClusterïŒã®èŠåïŒUAX #29ïŒã«æºæ ããã
ã€ãŸããã人éã 1 æåãšèŠãªãåäœããæ£ããæ°ããããã// ãèŠãç®ã® 1 æåãã§åæãã var e = StringInfo.GetTextElementEnumerator("ããð ®·ðšâð©âð§"); while (e.MoveNext()) Console.WriteLine(e.GetTextElement()); // ãã â çµåæåïŒã + æ¿ç¹ïŒã 1 ã€ã«ãŸãšãŸã // ð ®· â ãµãã²ãŒã ãã¢ã 1 〠// ðšâð©âð§ â ZWJ ã§ç¹ãã£ãçµµæåã 1 ã€// çµåæåïŒMark ã«ããŽãªïŒãå«ãã bool hasCombining = s.Any(c => { var cat = CharUnicodeInfo.GetUnicodeCategory(c); return cat == UnicodeCategory.NonSpacingMark || cat == UnicodeCategory.SpacingCombiningMark || cat == UnicodeCategory.EnclosingMark; });**ããå®åçãªã®ã¯ãæ£èŠåããŠããæ¯èŒããã**æ¹æ³ã§ããã
// åææžã¿æåã«å¯ããïŒNFCïŒ string nfc = s.Normalize(NormalizationForm.FormC); // ããã㯠2 éãã®è¡šçŸããã "ã" (U+304C) â åææžã¿ïŒNFCïŒ "ã" + "ã" (U+304B U+3099) â åè§£ïŒNFDïŒ // æ£èŠåããã°ãã©ã¡ããåãã«ãªã Assert.Equal("ã", "ãã".Normalize(NormalizationForm.FormC));
åœ¢åŒ å 容 çšé NFC åææžã¿ã«å¯ãã DB ä¿åã»æ¯èŒã®æ¢å®ãWindows ã®æ £ç¿ NFD åè§£ãã macOS ã®ãã¡ã€ã«åããã NFKC åæïŒäºæåè§£ïŒå šè§âåè§ãâ â 1ïŒ æ€çŽ¢ããŒã®æ£èŠå NFKD åè§£ïŒäºæåè§£ åäž NFKC ã¯åœ±é¿ã倧ããç¹ã«æ³šæããã
ã±â(æ ª)ãââ1ãâAã®ããã«å€ããããã
æ°åãäœæããã®ãŸãŸ NFKC ãããšãåæã倱ãããã
æ€çŽ¢çšã®ããŒãå¥ã«æã€ã®ãæ£ããèšèšã§ããããmacOS ç±æ¥ã®ãã¡ã€ã«åããæ¿ç¹ãåãããŠãããåé¡ã macOSïŒHFS+ïŒã¯ãNFD çžåœãã§ãã¡ã€ã«åãä¿åãã â ãã¬ãããã« + ããã® 2 æåãšããŠå±ã â Windows åŽã§æ€çŽ¢ãäžèŽããªã 察çïŒ åä¿¡æã« NFC æ£èŠåãã
ãµãã²ãŒã ãã¢æåã»çµåæåã¯ã
- éåžžã® Length ãã§ãã¯ã§ã¯ã2 æååãšããŠè¡šç€ºãããããã ããèŠãç®ã®æå㯠1 æåã
- ãŸããããã°ã©ã äžã§ã®ãã€ã衚çŸïŒUTF-16ïŒã§ã®ãã€ãé·ã¯ãéåžžã®æåã 2 ãã€ãã§ããã®ã«å¯Ÿãã4 ãã€ãã
ãµãã²ãŒã ãã¢æåã»çµåæåãå«ãæååã®èŠãç®ã®æååé·ã調ã¹ãå Žåã¯ã
- System.Globalization åå空éã® StringInfo ã¯ã©ã¹ã䜿çšããã
- string.Lengthãstring.Substring ãªã©ã¯ååçŠæ¢
ïŒstring.Length ã¯ãæååã®ãã€ãé·ã調æ»ããå Žåãªã©ã¯äœ¿çšå¯èœïŒ - ãã ãã.NET Framework 1.1 以åã®ã©ã³ã¿ã€ã ã§ã¯ã
ãã®ã¯ã©ã¹ã®ä»æ§ãç°ãªãäžèšã®æ§ã«å©çšã§ããªãã
/// <summary>æååæ
å ±ã®è¡šç€º</summary>
/// <param name="strSurrogatesPair">æåå</param>
private void GetStringInfo(string strSurrogatesPair)
{
// System.Globalization.StringInfoã䜿çšããã
StringInfo si = new StringInfo(strSurrogatesPair);
// æååã衚瀺
MessageBox.Show(strSurrogatesPair);
// é·ãã衚瀺ïŒ
MessageBox.Show("é·ãïŒæååé·ïŒïŒïŒ" + strSurrogatesPair.Length);
// é·ãã衚瀺ïŒ
MessageBox.Show("é·ãïŒæååé·ïŒïŒïŒ" + si.LengthInTextElements);
// é·ãã衚瀺ïŒ
MessageBox.Show("é·ãïŒããã°ã©ã äžïŒUTF-16ïŒã§ã®ãã€ãé·ïŒïŒ" +
Encoding.Unicode.GetBytes(strSurrogatesPair).Length);
}- [åè]:Microsoft Learn > .NET Framework ã¯ã©ã¹ ã©ã€ãã©ãª > StringInfo ã¡ã³ã
https://learn.microsoft.com/ja-jp/dotnet/api/system.globalization.stringinfo
è£è¶³ïŒãLength ã¯ååçŠæ¢ãã®æå³ïŒ: åæã®ãã®æéã¯
匷ã衚çŸã ããæ¹åã¯æ£ããããã ã
ãäœãæ°ãããããã§çããå€ãããããæŽçããŠãããstring s = "ãð ®·ãã"; // ã + ð ®·ïŒãµãã²ãŒãïŒ+ ã + æ¿ç¹ s.Length // 5ïŒUTF-16 ã®åäœæ°ïŒ s.EnumerateRunes().Count() // 4ïŒã³ãŒããã€ã³ãæ°ïŒ new StringInfo(s).LengthInTextElements // 3ïŒèŠãç®ã®æåæ°ïŒâ Encoding.UTF8.GetByteCount(s) // 13ïŒUTF-8 ã®ãã€ãæ°ïŒ Encoding.Unicode.GetByteCount(s) // 10ïŒUTF-16 ã®ãã€ãæ°ïŒ
ç®ç 䜿ããã® å ¥åæ¬ã®ãâæåãŸã§ãã®å€å® LengthInTextElementsïŒå©çšè ã®æèŠã«äžèŽïŒDB ã® nvarchar(n)ã«åãŸããs.LengthïŒSQL Server ã® n 㯠UTF-16 åäœïŒãã¡ã€ã«ã»éä¿¡ã®ãµã€ãºèŠç©ã Encoding.UTF8.GetByteCountåºå®é·ãã¡ã€ã«ïŒCP932ïŒã®æ¡æ° Encoding.GetEncoding(932).GetByteCountåã«ç©ºãã©ãã string.IsNullOrEmptyïŒLength == 0ããæç¢ºïŒ
Substringãå±éºãªçç±ãåãã§ããã// â ãµãã²ãŒã ãã¢ã®éäžã§åããšãå£ããæåãã§ãã "ð ®·éå®¶".Substring(0, 1); // å€ç«ãµãã²ãŒãïŒè¡šç€ºã¯ "?"ïŒ // â èŠãç®ã®æåã§åã var si = new StringInfo("ð ®·éå®¶"); si.SubstringByTextElements(0, 1); // "ð ®·"ãâŠãã§çç¥è¡šç€ºããåŠçã¯ããã®çœ ã®å žåã§ããã
çµµæåãçµåæåãå«ãå ¥åïŒçŸåšã¯ããæ®éã«æ¥ãïŒã§ã
æåãå£ããïŒè±è ã«ãªããšããäžå ·åã«ãªããç§»è¡ã¡ã¢: åæã®ã.NET Framework 1.1 以åã®ã©ã³ã¿ã€ã ã§ã¯
ãã®ã¯ã©ã¹ã®ä»æ§ãç°ãªãããšããæ³šèšã¯ã
çŸåšã¯èæ ®äžèŠã§ããïŒ.NET Framework 1.1 㯠2013 幎ã«ãµããŒãçµäºïŒã
ãããã.NET 5 ã§StringInfoã UAX #29 æºæ ã«ä¿®æ£ãããããšã®æ¹ã
çŸåšã®é¢å¿äºã§ããïŒãã以åã¯çµµæåã®æ±ããäžæ£ç¢ºã ã£ãïŒã
ãšã³ã³ãŒãã£ã³ã°ã䜿çšããŠå¯éãã§ãã¯ãããã
ç¹å®ã®ãšã³ã³ãŒãã£ã³ã°ã®
- ã³ãŒãããŒãžç¯å²å ã®æåã§ãããïŒ
- Unicode ããã®åæ¹åã®ãšã³ã³ãŒãã£ã³ã°ãå¯èœãïŒ
ããã§ãã¯ã§ããã
-
以äžã®ããã«ãšã³ã³ãŒãã£ã³ã°ãè¡ãã
- â Unicode æåå
- â MS932 ãšã³ã³ãŒãã£ã³ã°
- â â¡MS932 æååïŒãã€ãé åïŒ
- â MS932 ãã³ãŒãã£ã³ã°
- â â¢Unicode æåå
-
äžèšã®çµæããã
â Unicode æååãšãâ¢Unicode æååãæ¯èŒãïŒãïŒããã§ãã¯ããã
è£è¶³ïŒå®è£ ãšèœãšã穎ïŒ: ãã®æ¹åŒãæãå®åçã§ããã
æå衚ãæããã«ãçžæã«éãããããçŽæ¥ç¢ºãããããã// .NET Core 以éã¯æåã« 1 床ã ãç»é²ãå¿ èŠ Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); static bool IsRoundTrippable(string s, int codePage) { var enc = Encoding.GetEncoding(codePage); return enc.GetString(enc.GetBytes(s)) == s; } IsRoundTrippable("é«å³¶å±", 932); // true ïŒCP932 ã«ããïŒ IsRoundTrippable("ð ®·éå®¶", 932); // falseïŒJIS2004 ã®æåïŒ IsRoundTrippable("café", 932); // falseïŒÃ© ã CP932 ã«ãªãïŒèœãšã穎 â ïŒæ¢å®ã§ã¯å€±æãã?ãã«åããŠåãããªã
äžã®å®è£ ã§ false ã¯è¿ããã
ãã©ã®æåãé§ç®ã ã£ãããã¯åãããªãã
äŸå€ãåºãèšå®ã«ãããšãäœçœ®ãç¹å®ã§ãããvar enc = Encoding.GetEncoding(932, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); try { enc.GetBytes(s); } catch (EncoderFallbackException ex) { // ex.Index âŠ äœæåç®ã // ex.CharUnknown âŠ å€æã§ããªãã£ãæå }èœãšã穎 â¡ïŒæ³¢ããã·ã¥åé¡ã§ãåŸåŸ©ããã®ã«å€ãå€ããã
"ã"(U+301C) â CP932 â 0x8160 â Unicode â "ïœ"(U+FF5E) â åŸåŸ©ãã§ãã¯ã¯ãfalseãã«ãªã â ããããèŠãç®ã¯åãã§ãå®åäžã¯ãéããŠãããã©ã¡ããæ£ãšãããã¯æ¥å倿ã§ãã
ïŒãšã³ã³ãŒãã£ã³ã° ã®äºäŸïŒïŒã
å³å¯ã«å€å®ããããªããäºåã«æ£èŠåããŠããåŸåŸ©ããããèœãšã穎 â¢ïŒéè€ç¬Šå·åãããæå
NEC éžå® IBM æ¡åŒµæåã¯ãåŸåŸ©ã§å¥ã®ãã€ãå€ã«ãªããã
Unicode ã«æ»ãã°åãæåãªã®ã§ã
ãã®æ¹åŒã§ã¯æ€åºãããªãïŒïŒéãããšå€å®ãããïŒã
ãã€ãå€ã®äžèŽãŸã§æ±ãããªãããã€ãååå£«ãæ¯èŒãããèœãšã穎 â£ïŒæ§èœ
1 æåããšã«
GetEncodingãåŒã¶å®è£ ã¯é ãã
Encodingã€ã³ã¹ã¿ã³ã¹ã¯äœ¿ãåãïŒã¹ã¬ãã ã»ãŒãïŒã// â ã«ãŒãã®äžã§æ¯åååŸ foreach (var s in list) { Encoding.GetEncoding(932)... } // â 1 床ã ãååŸããŠäœ¿ãåã static readonly Encoding Cp932 = Encoding.GetEncoding(932);
è£è¶³ïŒå ¥åãã§ãã¯ã®çŸåšã®èšèšïŒ: 3 æ¹åŒãèžãŸããäžã§ã®ã
çŸåšã®å®åçãªæéããŸãšãããâ ãŸãããªãå¶éããã®ãããæ±ºãã
çç± é©åãªææ®µ 飿ºå ã CP932 ããåããããªã å¯éãã§ãã¯ïŒçžæã®æåã³ãŒãã§ïŒ 垳祚ã®ãã©ã³ãã«åããªã ãã©ã³ãåŽã®å¯Ÿå¿æåã§åå¥ãã§ã㯠æ¥åã«ãŒã«ïŒæ°åã¯æŒ¢åã»ããªã®ã¿çïŒ æ£èŠè¡šçŸã«ããæåçš®ãã§ã㯠æååããæãïŒæŒ ç¶ãšïŒ å¶éããªããUTF-8 ã§éãæ¹ãæ ¹æ¬ç æåŸã®è¡ãéèŠã§ã
ã念ã®ãããã§æåãå¶éãããšãå©çšè ã®æ°åãå ¥åã§ããªã
ãšããåé¡ãçãã
å¶éã«ã¯å¿ ãçç±ãèŠããâ¡ å¶éãããªããå ¥å£ã§ã»æç¢ºãªã¡ãã»ãŒãžã§
â ãå ¥åã«èª€ãããããŸãã â ã3 æåç®ã®ãð ®·ãã¯ç»é²ã§ããŸããããåãã§ãå ¥åãã ãããã©ã®æåãé§ç®ããè¿ããå®è£ ã«ããŠãã
ïŒåè¿°ã®EncoderFallbackExceptionã®Index/CharUnknownïŒã⢠æ£èŠåã®ã¿ã€ãã³ã°ã決ãã
ãå ¥åæã NFC æ£èŠå â ä¿å ïŒmacOS ç±æ¥ã® NFD ãåžåããïŒ ãæ€çŽ¢æã NFKC æ£èŠåããå¥ã«ã©ã ã§çªãåããã ïŒå šè§ã»åè§ãäžžæ°åã®æºããåžåããïŒâ£ DB åŽãåããã
æšå¥š åã®å nvarcharïŒvarcharã¯ã³ãŒãããŒãžäŸåïŒSQL Server 2019 以é UTF-8 ç §åé åºã® varcharãéžã¹ãç §åé åº _SCä»ãïŒSupplementary Charactersããµãã²ãŒã ãã¢å¯Ÿå¿ïŒ
_SCãä»ããŠããªãç §åé åºã§ã¯ã
LEN()ãSUBSTRING()ããµãã²ãŒã ãã¢ãæ£ããæ±ããªãã
.NET åŽã®StringInfoãšåãåé¡ã DB åŽã«ããã
ïŒSQL ServerïŒã
- .NET ã§ã®æåãšã³ã³ãŒã
https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/character-encoding-introduction - System.Text.Rune æ§é äœ
https://learn.microsoft.com/ja-jp/dotnet/api/system.text.rune - System.Globalization.StringInfo ã¯ã©ã¹
https://learn.microsoft.com/ja-jp/dotnet/api/system.globalization.stringinfo - æååã§ã®æåã®æäœïŒæžèšçŽ ã¯ã©ã¹ã¿ïŒ
https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/character-encoding-introduction#grapheme-clusters - String.Normalize ã¡ãœãã
https://learn.microsoft.com/ja-jp/dotnet/api/system.string.normalize
Tags: ç§»è¡, .NETéçº, åœéå察å¿, æåã³ãŒã