ฉันมีข้อกำหนดที่ค่อนข้างคลุมเครือ แต่รู้สึกว่าควรเป็นไปได้โดยใช้ BCL
สำหรับบริบทผมแยกสตริงวันที่ / เวลาในNoda เวลา ฉันรักษาเคอร์เซอร์แบบลอจิคัลสำหรับตำแหน่งของฉันภายในสตริงอินพุต ดังนั้นในขณะที่สตริงที่สมบูรณ์อาจเป็น "3 มกราคม 2013" เคอร์เซอร์แบบลอจิคัลอาจอยู่ที่ "J"
ตอนนี้ฉันต้องแยกวิเคราะห์ชื่อเดือนโดยเปรียบเทียบกับชื่อเดือนที่รู้จักทั้งหมดสำหรับวัฒนธรรม:
- วัฒนธรรมที่อ่อนไหว
- ตัวพิมพ์เล็กและใหญ่
- จากจุดของเคอร์เซอร์ (ไม่ใช่ในภายหลังฉันต้องการดูว่าเคอร์เซอร์กำลัง "ดู" ชื่อเดือนของผู้สมัครหรือไม่)
- อย่างรวดเร็ว
- ... และฉันต้องรู้ว่าหลังจากนั้นใช้อักขระกี่ตัว
รหัสปัจจุบันCompareInfo.Compare
การทำเช่นนี้โดยทั่วไปจะทำงานโดยใช้ มันเป็นแบบนี้อย่างมีประสิทธิภาพ (สำหรับส่วนที่ตรงกัน - มีโค้ดมากกว่าของจริง แต่ไม่เกี่ยวข้องกับการจับคู่):
internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
return compareInfo.Compare(text, position, candidate.Length,
candidate, 0, candidate.Length,
CompareOptions.IgnoreCase) == 0;
}
อย่างไรก็ตามขึ้นอยู่กับผู้สมัครและภูมิภาคที่เราเปรียบเทียบว่ามีความยาวเท่ากัน ดีเกือบตลอดเวลา แต่ไม่ดีในบางกรณี สมมติว่าเรามีสิ่งที่ต้องการ:
// U+00E9 is a single code point for e-acute
var text = "x b\u00e9d y";
int position = 2;
// e followed by U+0301 still means e-acute, but from two code points
var candidate = "be\u0301d";
ตอนนี้การเปรียบเทียบของฉันจะล้มเหลว ฉันสามารถใช้IsPrefix
:
if (compareInfo.IsPrefix(text.Substring(position), candidate,
CompareOptions.IgnoreCase))
แต่:
- นั่นทำให้ฉันต้องสร้างสตริงย่อยซึ่งฉันควรหลีกเลี่ยงจริงๆ (ฉันกำลังดู Noda Time เป็นไลบรารีระบบอย่างมีประสิทธิภาพการแยกวิเคราะห์ประสิทธิภาพอาจมีความสำคัญสำหรับลูกค้าบางราย)
- มันไม่ได้บอกฉันว่าจะต้องเลื่อนเคอร์เซอร์ไปไกลแค่ไหนในภายหลัง
ในความเป็นจริงผมขอสงสัยนี้จะไม่เกิดขึ้นบ่อยมาก ... แต่ฉันจริงๆชอบที่จะทำสิ่งที่ถูกต้องที่นี่ ฉันก็อยากจะทำได้โดยไม่ต้องเป็นผู้เชี่ยวชาญ Unicode หรือลงมือทำเอง :)
(ยกเป็นบั๊ก 210ใน Noda Time เผื่อว่าใครอยากติดตามบทสรุปในท้ายที่สุด)
ฉันชอบความคิดของการทำให้เป็นมาตรฐาน ฉันต้องตรวจสอบโดยละเอียดเพื่อ a) ความถูกต้องและ b) ประสิทธิภาพ สมมติว่าฉันสามารถทำให้มันทำงานได้อย่างถูกต้องฉันก็ยังไม่แน่ใจว่ามันจะคุ้มค่ากับการเปลี่ยนแปลงทั้งหมดได้อย่างไร - มันเป็นสิ่งที่อาจไม่เคยเกิดขึ้นจริงในชีวิตจริง แต่อาจส่งผลกระทบต่อประสิทธิภาพของผู้ใช้ทั้งหมดของฉัน: (
ฉันได้ตรวจสอบ BCL ด้วยซึ่งดูเหมือนจะไม่สามารถจัดการสิ่งนี้ได้อย่างถูกต้อง โค้ดตัวอย่าง:
using System;
using System.Globalization;
class Test
{
static void Main()
{
var culture = (CultureInfo) CultureInfo.InvariantCulture.Clone();
var months = culture.DateTimeFormat.AbbreviatedMonthNames;
months[10] = "be\u0301d";
culture.DateTimeFormat.AbbreviatedMonthNames = months;
var text = "25 b\u00e9d 2013";
var pattern = "dd MMM yyyy";
DateTime result;
if (DateTime.TryParseExact(text, pattern, culture,
DateTimeStyles.None, out result))
{
Console.WriteLine("Parsed! Result={0}", result);
}
else
{
Console.WriteLine("Didn't parse");
}
}
}
การเปลี่ยนชื่อเดือนที่กำหนดเองเป็นเพียง "bed" โดยมีค่าข้อความเป็น "bEd" จะแยกวิเคราะห์
เอาล่ะจุดข้อมูลเพิ่มเติมเล็กน้อย:
ค่าใช้จ่ายในการใช้งาน
Substring
และIsPrefix
มีความสำคัญ แต่ไม่น่ากลัว ในตัวอย่าง "วันศุกร์ที่ 12 เมษายน 2556 20:28:42 น." บนแล็ปท็อปสำหรับการพัฒนาของฉันมันจะเปลี่ยนจำนวนการดำเนินการแยกวิเคราะห์ที่ฉันสามารถดำเนินการได้ในหนึ่งวินาทีจากประมาณ 460K เป็นประมาณ 400K ฉันควรหลีกเลี่ยงการชะลอตัวนั้นถ้าเป็นไปได้ แต่ก็ไม่เลวร้ายเกินไปNormalization มีความเป็นไปได้น้อยกว่าที่คิด - เพราะไม่มีใน Portable Class Libraries ผมอาจจะใช้เพียงสำหรับการไม่ จำกัด สร้างอนุญาตให้บมจสร้างจะเป็นเล็ก ๆ น้อย ๆ ที่ถูกต้องน้อย การทดสอบประสิทธิภาพสำหรับการทำให้เป็นมาตรฐาน (
string.IsNormalized
) ทำให้ประสิทธิภาพลดลงเหลือประมาณ 445K การโทรต่อวินาทีซึ่งฉันสามารถใช้งานได้ ฉันยังไม่แน่ใจว่ามันทำทุกอย่างที่ฉันต้องการตัวอย่างเช่นชื่อเดือนที่มี "ß" ควรตรงกับ "ss" ในหลายวัฒนธรรมฉันเชื่อว่า ... และการทำให้เป็นมาตรฐานไม่ได้ทำเช่นนั้น
text
msdn.microsoft.com/en-us/library/ms143031.aspx แต่ถ้านานมากก็จะเสียเวลาค้นหามากเกินกว่าที่ต้องการ if (compareInfo.IndexOf(text, candidate, position, options) == position)
text
String
คลาสไปเลยในอินสแตนซ์นี้และใช้ไฟล์Char[]
. คุณจะเขียนโค้ดได้มากขึ้น แต่นั่นคือสิ่งที่เกิดขึ้นเมื่อคุณต้องการประสิทธิภาพสูง ... หรือบางทีคุณควรจะเขียนโปรแกรมใน C ++ / CLI ;-)