The Labs \ Source Viewer \ SSCLI \ System.Globalization \ FORMATFLAGS

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. ////////////////////////////////////////////////////////////////////////////
  16. //
  17. // DateTimeFormatInfoScanner
  18. //
  19. // Scan a specified DateTimeFormatInfo to search for data used in DateTime.Parse()
  20. //
  21. // The data includes:
  22. //
  23. // DateWords: such as "de" used in es-ES (Spanish) LongDatePattern.
  24. // Postfix: such as "ta" used in fi-FI after the month name.
  25. //
  26. ////////////////////////////////////////////////////////////////////////////
  27. namespace System.Globalization
  28. {
  29.     using System;
  30.     using System.Globalization;
  31.     using System.Collections;
  32.     using System.Text;
  33.    
  34.     //
  35.     // from LocaleEx.txt header
  36.     //
  37.     //; IFORMATFLAGS
  38.     //; Parsing/formatting flags.
  39.     internal enum FORMATFLAGS
  40.     {
  41.         None = 0,
  42.         UseGenitiveMonth = 1,
  43.         UseLeapYearMonth = 2,
  44.         UseSpacesInMonthNames = 4,
  45.         UseHebrewParsing = 8,
  46.         UseSpacesInDayNames = 16,
  47.         // Has spaces or non-breaking space in the day names.
  48.         UseDigitPrefixInTokens = 32
  49.         // Has token starting with numbers.
  50.     }
  51.    
  52.     //
  53.     // To change in CalendarId you have to do the same change in Calendar.cs
  54.     // To do: make the definintion shared between these two files.
  55.     //
  56.    
  57.     internal enum CalendarId : ushort
  58.     {
  59.         GREGORIAN = 1,
  60.         // Gregorian (localized) calendar
  61.         GREGORIAN_US = 2,
  62.         // Gregorian (U.S.) calendar
  63.         JAPAN = 3,
  64.         // Japanese Emperor Era calendar
  65.         TAIWAN = 4,
  66.         // Taiwan Era calendar
  67.         KOREA = 5,
  68.         // Korean Tangun Era calendar
  69.         HIJRI = 6,
  70.         // Hijri (Arabic Lunar) calendar
  71.         THAI = 7,
  72.         // Thai calendar
  73.         HEBREW = 8,
  74.         // Hebrew (Lunar) calendar
  75.         GREGORIAN_ME_FRENCH = 9,
  76.         // Gregorian Middle East French calendar
  77.         GREGORIAN_ARABIC = 10,
  78.         // Gregorian Arabic calendar
  79.         GREGORIAN_XLIT_ENGLISH = 11,
  80.         // Gregorian Transliterated English calendar
  81.         GREGORIAN_XLIT_FRENCH = 12,
  82.         // Note that all calendars after this point are MANAGED ONLY for now.
  83.         JULIAN = 13,
  84.         JAPANESELUNISOLAR = 14,
  85.         CHINESELUNISOLAR = 15,
  86.         SAKA = 16,
  87.         // reserved to match Office but not implemented in our code
  88.         LUNAR_ETO_CHN = 17,
  89.         // reserved to match Office but not implemented in our code
  90.         LUNAR_ETO_KOR = 18,
  91.         // reserved to match Office but not implemented in our code
  92.         LUNAR_ETO_ROKUYOU = 19,
  93.         // reserved to match Office but not implemented in our code
  94.         KOREANLUNISOLAR = 20,
  95.         TAIWANLUNISOLAR = 21,
  96.         PERSIAN = 22,
  97.         UMALQURA = 23
  98.     }
  99.    
  100.     internal class DateTimeFormatInfoScanner
  101.     {
  102.         // Special prefix-like flag char in DateWord array.
  103.        
  104.         // Use char in PUA area since we won't be using them in real data.
  105.         // The char used to tell a read date word or a month postfix. A month postfix
  106.         // is "ta" in the long date pattern like "d. MMMM'ta 'yyyy" for fi-FI.
  107.         // In this case, it will be stored as "\xfffeta" in the date word array.
  108.         internal const char MonthPostfixChar = '';
  109.        
  110.         // Add ignorable symbol in a DateWord array.
  111.        
  112.         // hu-HU has:
  113.         // shrot date pattern: yyyy. MM. dd.;yyyy-MM-dd;yy-MM-dd
  114.         // long date pattern: yyyy. MMMM d.
  115.         // Here, "." is the date separator (derived from short date pattern). However,
  116.         // "." also appear at the end of long date pattern. In this case, we just
  117.         // "." as ignorable symbol so that the DateTime.Parse() state machine will not
  118.         // treat the additional date separator at the end of y,m,d pattern as an error
  119.         // condition.
  120.         internal const char IgnorableSymbolChar = '';
  121.        
  122.         // Known CJK suffix
  123.         internal const string CJKYearSuff = "年";
  124.         internal const string CJKMonthSuff = "月";
  125.         internal const string CJKDaySuff = "日";
  126.        
  127.         internal const string KoreanYearSuff = "년";
  128.         internal const string KoreanMonthSuff = "월";
  129.         internal const string KoreanDaySuff = "일";
  130.        
  131.         internal const string KoreanHourSuff = "시";
  132.         internal const string KoreanMinuteSuff = "분";
  133.         internal const string KoreanSecondSuff = "초";
  134.        
  135.         internal const string CJKHourSuff = "時";
  136.         internal const string ChineseHourSuff = "时";
  137.        
  138.         internal const string CJKMinuteSuff = "分";
  139.         internal const string CJKSecondSuff = "秒";
  140.        
  141.         // The collection fo date words & postfix.
  142.         internal ArrayList m_dateWords = new ArrayList();
  143.         // Hashtable for the known words.
  144.         static internal Hashtable m_knownWords;
  145.        
  146.         Hashtable KnownWords {
  147.             get {
  148.                 if (m_knownWords == null) {
  149.                     Hashtable temp = new Hashtable();
  150.                     // Add known words into the hash table.
  151.                    
  152.                     // Skip these special symbols.
  153.                     temp.Add("/", String.Empty);
  154.                     temp.Add("-", String.Empty);
  155.                     temp.Add(".", String.Empty);
  156.                     // Skip known CJK suffixes.
  157.                     temp.Add(CJKYearSuff, String.Empty);
  158.                     temp.Add(CJKMonthSuff, String.Empty);
  159.                     temp.Add(CJKDaySuff, String.Empty);
  160.                     temp.Add(KoreanYearSuff, String.Empty);
  161.                     temp.Add(KoreanMonthSuff, String.Empty);
  162.                     temp.Add(KoreanDaySuff, String.Empty);
  163.                     temp.Add(KoreanHourSuff, String.Empty);
  164.                     temp.Add(KoreanMinuteSuff, String.Empty);
  165.                     temp.Add(KoreanSecondSuff, String.Empty);
  166.                     temp.Add(CJKHourSuff, String.Empty);
  167.                     temp.Add(ChineseHourSuff, String.Empty);
  168.                     temp.Add(CJKMinuteSuff, String.Empty);
  169.                     temp.Add(CJKSecondSuff, String.Empty);
  170.                    
  171.                     m_knownWords = temp;
  172.                 }
  173.                 return (m_knownWords);
  174.             }
  175.         }
  176.        
  177.         ////////////////////////////////////////////////////////////////////////////
  178.         //
  179.         // Parameters:
  180.         // pattern: The pattern to be scanned.
  181.         // currentIndex: the current index to start the scan.
  182.         //
  183.         // Returns:
  184.         // Return the index with the first character that is a letter, which will
  185.         // be the start of a date word.
  186.         // Note that the index can be pattern.Length if we reach the end of the string.
  187.         //
  188.         ////////////////////////////////////////////////////////////////////////////
  189.         static internal int SkipWhiteSpacesAndNonLetter(string pattern, int currentIndex)
  190.         {
  191.             while (currentIndex < pattern.Length) {
  192.                 char ch = pattern[currentIndex];
  193.                 if (ch == '\\') {
  194.                     // Escaped character. Look ahead one character.
  195.                     currentIndex++;
  196.                     if (currentIndex < pattern.Length) {
  197.                         ch = pattern[currentIndex];
  198.                         if (ch == '\'') {
  199.                             // Skip the leading single quote. We will
  200.                             // stop at the first letter.
  201.                             continue;
  202.                         }
  203.                         // Fall thru to check if this is a letter.
  204.                     }
  205.                     else {
  206.                         // End of string
  207.                         break;
  208.                     }
  209.                 }
  210.                 if (Char.IsLetter(ch) || ch == '\'' || ch == '.') {
  211.                     break;
  212.                 }
  213.                 // Skip the current char since it is not a letter.
  214.                 currentIndex++;
  215.             }
  216.             return (currentIndex);
  217.         }
  218.        
  219.         ////////////////////////////////////////////////////////////////////////////
  220.         //
  221.         // A helper to add the found date word or month postfix into ArrayList for date words.
  222.         //
  223.         // Parameters:
  224.         // formatPostfix: What kind of postfix this is.
  225.         // Possible values:
  226.         // null: This is a regular date word
  227.         // "MMMM": month postfix
  228.         // word: The date word or postfix to be added.
  229.         //
  230.         ////////////////////////////////////////////////////////////////////////////
  231.         internal void AddDateWordOrPostfix(string formatPostfix, string str)
  232.         {
  233.             if (str.Length > 0) {
  234.                 // Some cultures use . like an abbreviation
  235.                 if (str.Equals(".")) {
  236.                     AddIgnorableSymbols(".");
  237.                     return;
  238.                 }
  239.                 if (KnownWords[str] == null) {
  240.                     if (m_dateWords == null) {
  241.                         m_dateWords = new ArrayList();
  242.                     }
  243.                     if (formatPostfix == "MMMM") {
  244.                         // Add the word into the ArrayList as "\xfffe" + real month postfix.
  245.                         string temp = MonthPostfixChar + str;
  246.                         if (!m_dateWords.Contains(temp)) {
  247.                             m_dateWords.Add(temp);
  248.                         }
  249.                     }
  250.                     else {
  251.                         if (!m_dateWords.Contains(str)) {
  252.                             m_dateWords.Add(str);
  253.                         }
  254.                         if (str[str.Length - 1] == '.') {
  255.                             // Old version ignore the trialing dot in the date words. Support this as well.
  256.                             string strWithoutDot = str.Substring(0, str.Length - 1);
  257.                             if (!m_dateWords.Contains(strWithoutDot)) {
  258.                                 m_dateWords.Add(strWithoutDot);
  259.                             }
  260.                            
  261.                         }
  262.                     }
  263.                 }
  264.             }
  265.            
  266.         }
  267.        
  268.         ////////////////////////////////////////////////////////////////////////////
  269.         //
  270.         // Scan the pattern from the specified index and add the date word/postfix
  271.         // when appropriate.
  272.         //
  273.         // Parameters:
  274.         // pattern: The pattern to be scanned.
  275.         // index: The starting index to be scanned.
  276.         // formatPostfix: The kind of postfix to be scanned.
  277.         // Possible values:
  278.         // null: This is a regular date word
  279.         // "MMMM": month postfix
  280.         //
  281.         //
  282.         ////////////////////////////////////////////////////////////////////////////
  283.         internal int AddDateWords(string pattern, int index, string formatPostfix)
  284.         {
  285.             // Skip any whitespaces so we will start from a letter.
  286.             int newIndex = SkipWhiteSpacesAndNonLetter(pattern, index);
  287.             if (newIndex != index && formatPostfix != null) {
  288.                 // There are whitespaces. This will not be a postfix.
  289.                 formatPostfix = null;
  290.             }
  291.             index = newIndex;
  292.            
  293.             // This is the first char added into dateWord.
  294.             // Skip all non-letter character. We will add the first letter into DateWord.
  295.             StringBuilder dateWord = new StringBuilder();
  296.             // We assume that date words should start with a letter.
  297.             // Skip anything until we see a letter.
  298.            
  299.             while (index < pattern.Length) {
  300.                 char ch = pattern[index];
  301.                 if (ch == '\'') {
  302.                     // We have seen the end of quote. Add the word if we do not see it before,
  303.                     // and break the while loop.
  304.                     AddDateWordOrPostfix(formatPostfix, dateWord.ToString());
  305.                     index++;
  306.                     break;
  307.                 }
  308.                 else if (ch == '\\') {
  309.                     //
  310.                     // Escaped character. Look ahead one character
  311.                     //
  312.                    
  313.                     // Skip escaped backslash.
  314.                     index++;
  315.                     if (index < pattern.Length) {
  316.                         dateWord.Append(pattern[index]);
  317.                         index++;
  318.                     }
  319.                 }
  320.                 else if (Char.IsWhiteSpace(ch)) {
  321.                     // Found a whitespace. We have to add the current date word/postfix.
  322.                     AddDateWordOrPostfix(formatPostfix, dateWord.ToString());
  323.                     if (formatPostfix != null) {
  324.                         // Done with postfix. The rest will be regular date word.
  325.                         formatPostfix = null;
  326.                     }
  327.                     // Reset the dateWord.
  328.                     dateWord.Length = 0;
  329.                     index++;
  330.                 }
  331.                 else {
  332.                     dateWord.Append(ch);
  333.                     index++;
  334.                 }
  335.             }
  336.             return (index);
  337.         }
  338.        
  339.         ////////////////////////////////////////////////////////////////////////////
  340.         //
  341.         // A simple helper to find the repeat count for a specified char.
  342.         //
  343.         ////////////////////////////////////////////////////////////////////////////
  344.         static internal int ScanRepeatChar(string pattern, char ch, int index, out int count)
  345.         {
  346.             count = 1;
  347.             while (++index < pattern.Length && pattern[index] == ch) {
  348.                 count++;
  349.             }
  350.             // Return the updated position.
  351.             return (index);
  352.         }
  353.        
  354.         ////////////////////////////////////////////////////////////////////////////
  355.         //
  356.         // Add the text that is a date separator but is treated like ignroable symbol.
  357.         // E.g.
  358.         // hu-HU has:
  359.         // shrot date pattern: yyyy. MM. dd.;yyyy-MM-dd;yy-MM-dd
  360.         // long date pattern: yyyy. MMMM d.
  361.         // Here, "." is the date separator (derived from short date pattern). However,
  362.         // "." also appear at the end of long date pattern. In this case, we just
  363.         // "." as ignorable symbol so that the DateTime.Parse() state machine will not
  364.         // treat the additional date separator at the end of y,m,d pattern as an error
  365.         // condition.
  366.         //
  367.         ////////////////////////////////////////////////////////////////////////////
  368.        
  369.         internal void AddIgnorableSymbols(string text)
  370.         {
  371.             if (m_dateWords == null) {
  372.                 // Create the date word array.
  373.                 m_dateWords = new ArrayList();
  374.             }
  375.             // Add the ingorable symbol into the ArrayList.
  376.             string temp = IgnorableSymbolChar + text;
  377.             if (!m_dateWords.Contains(temp)) {
  378.                 m_dateWords.Add(temp);
  379.             }
  380.         }
  381.        
  382.        
  383.         //
  384.         // Flag used to trace the date patterns (yy/yyyyy/M/MM/MMM/MMM/d/dd) that we have seen.
  385.         //
  386.         enum FoundDatePattern
  387.         {
  388.             None = 0,
  389.             FoundYearPatternFlag = 1,
  390.             FoundMonthPatternFlag = 2,
  391.             FoundDayPatternFlag = 4,
  392.             FoundYMDPatternFlag = 7
  393.             // FoundYearPatternFlag | FoundMonthPatternFlag | FoundDayPatternFlag;
  394.         }
  395.        
  396.         // Check if we have found all of the year/month/day pattern.
  397.         FoundDatePattern m_ymdFlags = FoundDatePattern.None;
  398.        
  399.        
  400.         ////////////////////////////////////////////////////////////////////////////
  401.         //
  402.         // Given a date format pattern, scan for date word or postfix.
  403.         //
  404.         // A date word should be always put in a single quoted string. And it will
  405.         // start from a letter, so whitespace and symbols will be ignored before
  406.         // the first letter.
  407.         //
  408.         // Examples of date word:
  409.         // 'de' in es-SP: dddd, dd' de 'MMMM' de 'yyyy
  410.         // "\x0443." in bg-BG: dd.M.yyyy '\x0433.'
  411.         //
  412.         // Example of postfix:
  413.         // month postfix:
  414.         // "ta" in fi-FI: d. MMMM'ta 'yyyy
  415.         // Currently, only month postfix is supported.
  416.         //
  417.         // Usage:
  418.         // Always call this with Framework-style pattern, instead of Windows style pattern.
  419.         // Windows style pattern uses '' for single quote, while .NET uses \'
  420.         //
  421.         ////////////////////////////////////////////////////////////////////////////
  422.         internal void ScanDateWord(string pattern)
  423.         {
  424.            
  425.             // Check if we have found all of the year/month/day pattern.
  426.             m_ymdFlags = FoundDatePattern.None;
  427.            
  428.             int i = 0;
  429.             while (i < pattern.Length) {
  430.                 char ch = pattern[i];
  431.                 int chCount;
  432.                
  433.                 switch (ch) {
  434.                     case '\'':
  435.                         // Find a beginning quote. Search until the end quote.
  436.                         i = AddDateWords(pattern, i + 1, null);
  437.                         break;
  438.                     case 'M':
  439.                         i = ScanRepeatChar(pattern, 'M', i, out chCount);
  440.                         if (chCount >= 4) {
  441.                             if (i < pattern.Length && pattern[i] == '\'') {
  442.                                 i = AddDateWords(pattern, i + 1, "MMMM");
  443.                             }
  444.                         }
  445.                         m_ymdFlags |= FoundDatePattern.FoundMonthPatternFlag;
  446.                         break;
  447.                     case 'y':
  448.                         i = ScanRepeatChar(pattern, 'y', i, out chCount);
  449.                         m_ymdFlags |= FoundDatePattern.FoundYearPatternFlag;
  450.                         break;
  451.                     case 'd':
  452.                         i = ScanRepeatChar(pattern, 'd', i, out chCount);
  453.                         if (chCount <= 2) {
  454.                             // Only count "d" & "dd".
  455.                             // ddd, dddd are day names. Do not count them.
  456.                             m_ymdFlags |= FoundDatePattern.FoundDayPatternFlag;
  457.                         }
  458.                         break;
  459.                     case '\\':
  460.                         // Found a escaped char not in a quoted string. Skip the current backslash
  461.                         // and its next character.
  462.                         i += 2;
  463.                         break;
  464.                     case '.':
  465.                         if (m_ymdFlags == FoundDatePattern.FoundYMDPatternFlag) {
  466.                             // If we find a dot immediately after the we have seen all of the y, m, d pattern.
  467.                             // treat it as a ignroable symbol. Check for comments in AddIgnorableSymbols for
  468.                             // more details.
  469.                             AddIgnorableSymbols(".");
  470.                             m_ymdFlags = FoundDatePattern.None;
  471.                         }
  472.                         i++;
  473.                         break;
  474.                     default:
  475.                         if (m_ymdFlags == FoundDatePattern.FoundYMDPatternFlag && !Char.IsWhiteSpace(ch)) {
  476.                             // We are not seeing "." after YMD. Clear the flag.
  477.                             m_ymdFlags = FoundDatePattern.None;
  478.                         }
  479.                         // We are not in quote. Skip the current character.
  480.                         i++;
  481.                         break;
  482.                 }
  483.             }
  484.         }
  485.        
  486.         ////////////////////////////////////////////////////////////////////////////
  487.         //
  488.         // Given a DTFI, get all of the date words.
  489.         //
  490.         ////////////////////////////////////////////////////////////////////////////
  491.        
  492.         internal string[] GetDateWordsOfDTFI(DateTimeFormatInfo dtfi)
  493.         {
  494.             // Enumarate all LongDatePatterns, and get the DateWords and scan for month postfix.
  495.             string[] datePatterns = dtfi.GetAllDateTimePatterns('D');
  496.             int i;
  497.             for (i = 0; i < datePatterns.Length; i++) {
  498.                 ScanDateWord(datePatterns[i]);
  499.             }
  500.             datePatterns = dtfi.GetAllDateTimePatterns('d');
  501.             for (i = 0; i < datePatterns.Length; i++) {
  502.                 ScanDateWord(datePatterns[i]);
  503.             }
  504.             // Scan the YearMonth patterns.
  505.             datePatterns = dtfi.GetAllDateTimePatterns('y');
  506.             for (i = 0; i < datePatterns.Length; i++) {
  507.                 ScanDateWord(datePatterns[i]);
  508.             }
  509.             string[] result = null;
  510.             if (m_dateWords != null && m_dateWords.Count > 0) {
  511.                 result = new string[m_dateWords.Count];
  512.                 for (i = 0; i < m_dateWords.Count; i++) {
  513.                     result[i] = (string)m_dateWords[i];
  514.                 }
  515.             }
  516.             return (result);
  517.         }
  518.        
  519.        
  520.         ////////////////////////////////////////////////////////////////////////////
  521.         //
  522.         // Scan the month names to see if genitive month names are used, and return
  523.         // the format flag.
  524.         //
  525.         ////////////////////////////////////////////////////////////////////////////
  526.         static internal FORMATFLAGS GetFormatFlagGenitiveMonth(string[] monthNames, string[] genitveMonthNames, string[] abbrevMonthNames, string[] genetiveAbbrevMonthNames)
  527.         {
  528.             // If we have different names in regular and genitive month names, use genitive month flag.
  529.             return ((!EqualStringArrays(monthNames, genitveMonthNames) || !EqualStringArrays(abbrevMonthNames, genetiveAbbrevMonthNames)) ? FORMATFLAGS.UseGenitiveMonth : 0);
  530.         }
  531.        
  532.         ////////////////////////////////////////////////////////////////////////////
  533.         //
  534.         // Scan the month names to see if spaces are used or start with a digit, and return the format flag
  535.         //
  536.         ////////////////////////////////////////////////////////////////////////////
  537.         static internal FORMATFLAGS GetFormatFlagUseSpaceInMonthNames(string[] monthNames, string[] genitveMonthNames, string[] abbrevMonthNames, string[] genetiveAbbrevMonthNames)
  538.         {
  539.             FORMATFLAGS formatFlags = 0;
  540.             formatFlags |= (ArrayElementsBeginWithDigit(monthNames) || ArrayElementsBeginWithDigit(genitveMonthNames) || ArrayElementsBeginWithDigit(abbrevMonthNames) || ArrayElementsBeginWithDigit(genetiveAbbrevMonthNames) ? FORMATFLAGS.UseDigitPrefixInTokens : 0);
  541.            
  542.             formatFlags |= (ArrayElementsHaveSpace(monthNames) || ArrayElementsHaveSpace(genitveMonthNames) || ArrayElementsHaveSpace(abbrevMonthNames) || ArrayElementsHaveSpace(genetiveAbbrevMonthNames) ? FORMATFLAGS.UseSpacesInMonthNames : 0);
  543.             return (formatFlags);
  544.         }
  545.        
  546.         ////////////////////////////////////////////////////////////////////////////
  547.         //
  548.         // Scan the day names and set the correct format flag.
  549.         //
  550.         ////////////////////////////////////////////////////////////////////////////
  551.         static internal FORMATFLAGS GetFormatFlagUseSpaceInDayNames(string[] dayNames, string[] abbrevDayNames)
  552.         {
  553.             return ((ArrayElementsHaveSpace(dayNames) || ArrayElementsHaveSpace(abbrevDayNames)) ? FORMATFLAGS.UseSpacesInDayNames : 0);
  554.            
  555.         }
  556.        
  557.         ////////////////////////////////////////////////////////////////////////////
  558.         //
  559.         // Check the calendar to see if it is HebrewCalendar and set the Hebrew format flag if necessary.
  560.         //
  561.         ////////////////////////////////////////////////////////////////////////////
  562.         static internal FORMATFLAGS GetFormatFlagUseHebrewCalendar(int calID)
  563.         {
  564.             return (calID == (int)CalendarId.HEBREW ? FORMATFLAGS.UseHebrewParsing | FORMATFLAGS.UseLeapYearMonth : 0);
  565.         }
  566.        
  567.        
  568.         //-----------------------------------------------------------------------------
  569.         // EqualStringArrays
  570.         // compares two string arrays and return true if all elements of the first
  571.         // array equals to all elmentsof the second array.
  572.         // otherwise it returns false.
  573.         //-----------------------------------------------------------------------------
  574.        
  575.         private static bool EqualStringArrays(string[] array1, string[] array2)
  576.         {
  577.             if (array1.Length != array2.Length) {
  578.                 return false;
  579.             }
  580.            
  581.             for (int i = 0; i < array1.Length; i++) {
  582.                 if (!array1[i].Equals(array2[i])) {
  583.                     return false;
  584.                 }
  585.             }
  586.            
  587.             return true;
  588.         }
  589.        
  590.         //-----------------------------------------------------------------------------
  591.         // ArrayElementsHaveSpace
  592.         // It checks all input array elements if any of them has space character
  593.         // returns true if found space character in one of the array elements.
  594.         // otherwise returns false.
  595.         //-----------------------------------------------------------------------------
  596.        
  597.         private static bool ArrayElementsHaveSpace(string[] array)
  598.         {
  599.            
  600.             for (int i = 0; i < array.Length; i++) {
  601.                 // it is faster to check for space character manually instead of calling IndexOf
  602.                 // so we don't have to go to native code side.
  603.                 for (int j = 0; j < array[i].Length; j++) {
  604.                     if (Char.IsWhiteSpace(array[i][j])) {
  605.                         return true;
  606.                     }
  607.                 }
  608.             }
  609.            
  610.             return false;
  611.         }
  612.        
  613.        
  614.         ////////////////////////////////////////////////////////////////////////////
  615.         //
  616.         // Check if any element of the array start with a digit.
  617.         //
  618.         ////////////////////////////////////////////////////////////////////////////
  619.         private static bool ArrayElementsBeginWithDigit(string[] array)
  620.         {
  621.            
  622.             for (int i = 0; i < array.Length; i++) {
  623.                 // it is faster to check for space character manually instead of calling IndexOf
  624.                 // so we don't have to go to native code side.
  625.                 if (array[i].Length > 0 && array[i][0] >= '0' && array[i][0] <= '9') {
  626.                     int index = 1;
  627.                     while (index < array[i].Length && array[i][index] >= '0' && array[i][index] <= '9') {
  628.                         // Skip other digits.
  629.                         index++;
  630.                     }
  631.                     if (index == array[i].Length) {
  632.                         return (false);
  633.                     }
  634.                    
  635.                     if (index == array[i].Length - 1) {
  636.                         // Skip known CJK month suffix.
  637.                         // CJK uses month name like "1\x6708", since \x6708 is a known month suffix,
  638.                         // we don't need the UseDigitPrefixInTokens since it is slower.
  639.                         switch (array[i][index]) {
  640.                             case '月':
  641.                             case '월':
  642.                                 // CJKMonthSuff
  643.                                 // KoreanMonthSuff
  644.                                 return (false);
  645.                         }
  646.                     }
  647.                     return (true);
  648.                 }
  649.             }
  650.            
  651.             return false;
  652.         }
  653.        
  654.     }
  655. }

Developer Fusion