/// <summary>
        /// Loads properties from the given kanji entity.
        /// </summary>
        /// <param name="se">Target SRS entry.</param>
        /// <param name="k">Kanji to load.</param>
        public static void LoadFromKanji(this SrsEntry se, KanjiEntity k)
        {
            // Compute the meaning string.
            string meaningString = string.Empty;
            foreach (KanjiMeaning km in k.Meanings)
            {
                meaningString += MultiValueFieldHelper.ReplaceSeparator(km.Meaning) + MultiValueFieldHelper.ValueSeparator;
            }
            meaningString = meaningString.Trim(
                new char[] { MultiValueFieldHelper.ValueSeparator });
            meaningString = MultiValueFieldHelper.Expand(meaningString);

            // Compute the reading string.
            string readingString = (k.OnYomi
                + MultiValueFieldHelper.ValueSeparator)
                + k.KunYomi;
            readingString = MultiValueFieldHelper.Expand(readingString
                .Trim(new char[] { MultiValueFieldHelper.ValueSeparator }));

            // Set values.
            se.Meanings = meaningString;
            se.Readings = readingString;
            se.AssociatedKanji = k.Character;
        }
Example #2
0
        /// <summary>
        /// Attempts to retrieve the kanji strokes SVG matching the given kanji inside the zip file.
        /// </summary>
        /// <param name="k">Target kanji.</param>
        /// <returns>A kanji strokes entity, never null, that contains either the retrieved data or an
        /// empty byte array when the entry was not found.</returns>
        private KanjiStrokes RetrieveSvg(KanjiEntity k)
        {
            KanjiStrokes strokes = new KanjiStrokes();
            strokes.FramesSvg = new byte[0];

            if (!k.UnicodeValue.HasValue)
            {
                return strokes;
            }

            ZipArchive svgZip = GetSvgZipArchive();
            string entryName = string.Format("{0}_frames.svg", k.UnicodeValue.Value);
            ZipArchiveEntry entry = svgZip.GetEntry(entryName);
            if (entry != null)
            {
                using (Stream stream = entry.Open())
                {
                    strokes.FramesSvg = StringCompressionHelper.Zip(StreamHelper.ReadToEnd(stream));
                    StringCompressionHelper.Unzip(strokes.FramesSvg);
                }
            }

            return strokes;
        }
Example #3
0
        /// <summary>
        /// Reads the KanjiDic2 file and outputs kanji entities parsed from the file.
        /// </summary>
        /// <returns>Kanji entities parsed from the file.</returns>
        private IEnumerable<KanjiEntity> ReadKanjiDic2()
        {
            // Load the KanjiDic2 file.
            XDocument xdoc = XDocument.Load(PathHelper.KanjiDic2Path);

            // Browse kanji nodes.
            foreach (XElement xkanji in xdoc.Root.Elements(XmlNode_Character))
            {
                // For each kanji node, read values.
                KanjiEntity kanji = new KanjiEntity();

                // Read the kanji character.
                kanji.Character = xkanji.Element(XmlNode_Literal).Value;

                // In the code point node...
                XElement xcodePoint = xkanji.Element(XmlNode_CodePoint);
                if (xcodePoint != null)
                {
                    // Try to read the unicode character value.
                    XElement xunicode = xcodePoint.Elements(XmlNode_CodePointValue)
                        .Where(x => x.ReadAttributeString(XmlAttribute_CodePointType) == XmlAttributeValue_CodePointUnicode)
                        .FirstOrDefault();

                    if (xunicode != null)
                    {
                        string unicodeValueString = xunicode.Value;
                        int intValue = 0;
                        if (int.TryParse(unicodeValueString, System.Globalization.NumberStyles.HexNumber, ParsingHelper.DefaultCulture, out intValue))
                        {
                            kanji.UnicodeValue = intValue;
                        }
                    }
                }

                // In the misc node...
                XElement xmisc = xkanji.Element(XmlNode_Misc);
                if (xmisc != null)
                {
                    // Try to read the grade, stroke count, frequency and JLPT level.
                    // Update: JLPT level is outdated in this file. Now using the JLPTKanjiList.
                    XElement xgrade = xmisc.Element(XmlNode_Grade);
                    XElement xstrokeCount = xmisc.Element(XmlNode_StrokeCount);
                    XElement xfrequency = xmisc.Element(XmlNode_Frequency);
                    //XElement xjlpt = xmisc.Element(XmlNode_JlptLevel);

                    if (xgrade != null) kanji.Grade = ParsingHelper.ParseShort(xgrade.Value);
                    if (xstrokeCount != null) kanji.StrokeCount = ParsingHelper.ParseShort(xstrokeCount.Value);
                    if (xfrequency != null) kanji.NewspaperRank = ParsingHelper.ParseInt(xfrequency.Value);
                    //if (xjlpt != null) kanji.JlptLevel = ParsingHelper.ParseShort(xjlpt.Value);
                }

                // Find the JLPT level using the dictionary.
                if (_jlptDictionary.ContainsKey(kanji.Character))
                {
                    kanji.JlptLevel = _jlptDictionary[kanji.Character];
                }

                // Find the frequency rank using the dictionary.
                if (_frequencyRankDictionary.ContainsKey(kanji.Character))
                {
                    kanji.MostUsedRank = _frequencyRankDictionary[kanji.Character];
                }

                // Find the WaniKani level using the dictionary.
                if (_waniKaniDictionary.ContainsKey(kanji.Character))
                {
                    kanji.WaniKaniLevel = _waniKaniDictionary[kanji.Character];
                }

                // In the reading/meaning node...
                XElement xreadingMeaning = xkanji.Element(XmlNode_ReadingMeaning);
                if (xreadingMeaning != null)
                {
                    // Read the nanori readings.
                    kanji.Nanori = string.Empty;
                    foreach (XElement xnanori in xreadingMeaning.Elements(XmlNode_Nanori))
                    {
                        kanji.Nanori += xnanori.Value + MultiValueFieldHelper.ValueSeparator;
                    }
                    kanji.Nanori = kanji.Nanori.Trim(MultiValueFieldHelper.ValueSeparator);

                    // Browse the reading group...
                    XElement xrmGroup = xreadingMeaning.Element(XmlNode_ReadingMeaningGroup);
                    if (xrmGroup != null)
                    {
                        // Read the on'yomi readings.
                        kanji.OnYomi = string.Empty;
                        foreach (XElement xonYomi in xrmGroup.Elements(XmlNode_Reading)
                            .Where(x => x.Attribute(XmlAttribute_ReadingType).Value == XmlAttributeValue_OnYomiReading))
                        {
                            kanji.OnYomi += xonYomi.Value + MultiValueFieldHelper.ValueSeparator;
                        }
                        kanji.OnYomi = KanaHelper.ToHiragana(kanji.OnYomi.Trim(MultiValueFieldHelper.ValueSeparator));

                        // Read the kun'yomi readings.
                        kanji.KunYomi = string.Empty;
                        foreach (XElement xkunYomi in xrmGroup.Elements(XmlNode_Reading)
                            .Where(x => x.Attribute(XmlAttribute_ReadingType).Value == XmlAttributeValue_KunYomiReading))
                        {
                            kanji.KunYomi += xkunYomi.Value + MultiValueFieldHelper.ValueSeparator;
                        }
                        kanji.KunYomi = kanji.KunYomi.Trim(MultiValueFieldHelper.ValueSeparator);

                        // Browse the meanings...
                        foreach (XElement xmeaning in xrmGroup.Elements(XmlNode_Meaning))
                        {
                            // Get the language and meaning.
                            XAttribute xlanguage = xmeaning.Attribute(XmlAttribute_MeaningLanguage);
                            string language = xlanguage != null ? xlanguage.Value.ToLower() : null;
                            string meaning = xmeaning.Value;

                            if (xlanguage == null || language.ToLower() == "en")
                            {
                                // Build a meaning.
                                KanjiMeaning kanjiMeaning = new KanjiMeaning() { Kanji = kanji, Language = language, Meaning = meaning };

                                // Add the meaning to the kanji.
                                kanji.Meanings.Add(kanjiMeaning);
                            }
                        }
                    }
                }

                // Return the kanji read and go to the next kanji node.
                yield return kanji;

                xkanji.RemoveAll();
            }
        }
Example #4
0
        /// <summary>
        /// Builds and returns the vocab filter SQL clauses from the given
        /// filters.
        /// </summary>
        internal string BuildVocabFilterClauses(List<DaoParameter> parameters,
            KanjiEntity kanji, string readingFilter, string meaningFilter)
        {
            bool isFiltered = false;

            string sqlKanjiFilter = string.Empty;
            if (kanji != null)
            {
                // Build the sql kanji filter clause.
                // Example with the kanji '達' :
                //
                // WHERE v.KanjiWriting LIKE '%達%'

                isFiltered = true;
                sqlKanjiFilter = "WHERE v." + SqlHelper.Field_Vocab_KanjiWriting
                    + " LIKE @kanji ";

                parameters.Add(new DaoParameter("@kanji", "%" + kanji.Character + "%"));
            }

            string sqlReadingFilter = string.Empty;
            if (!string.IsNullOrWhiteSpace(readingFilter))
            {
                // Build the sql reading filter clause.
                // Example with readingFilter="かな" :
                // 
                // WHERE v.KanaWriting LIKE '%かな%' OR
                // v.KanjiWriting LIKE '%かな%'

                sqlReadingFilter = isFiltered ? "AND " : "WHERE ";
                isFiltered = true;

                sqlReadingFilter += "(v." + SqlHelper.Field_Vocab_KanaWriting
                    + " LIKE @reading OR v." + SqlHelper.Field_Vocab_KanjiWriting
                    + " LIKE @reading) ";

                parameters.Add(new DaoParameter("@reading", "%" + readingFilter + "%"));
            }

            string sqlMeaningFilterJoins = string.Empty;
            string sqlMeaningFilter = string.Empty;
            if (!string.IsNullOrWhiteSpace(meaningFilter))
            {
                // Build the sql meaning filter clause and join clauses.
                // Example of filter clause with meaningFilter="test" :
                //
                // WHERE vme.Meaning LIKE '%test%'

                // First, build the join clause. This will be included before the filters.
                sqlMeaningFilterJoins = "JOIN " + SqlHelper.Table_Vocab_VocabMeaning
                    + " vvm ON (vvm." + SqlHelper.Field_Vocab_VocabMeaning_VocabId
                    + "=v." + SqlHelper.Field_Vocab_Id + ") "
                    + "JOIN " + SqlHelper.Table_VocabMeaning + " vm ON (vm."
                    + SqlHelper.Field_VocabMeaning_Id + "=vvm."
                    + SqlHelper.Field_Vocab_VocabMeaning_VocabMeaningId + ") ";
                // Ouch... it looks kinda like an obfuscated string... Sorry.
                // Basically, you just join the vocab to its meaning entries.

                // Once the join clauses are done, build the filter itself.
                // This will be applied as the last filter.
                sqlMeaningFilter = isFiltered ? "AND " : "WHERE ";
                isFiltered = true;

                sqlMeaningFilter += "vm." + SqlHelper.Field_VocabMeaning_Meaning
                    + " LIKE @meaning ";

                parameters.Add(new DaoParameter("@meaning", "%" + meaningFilter + "%"));
            }

            return sqlMeaningFilterJoins
                    + sqlKanjiFilter
                    + sqlReadingFilter
                    + sqlMeaningFilter;
        }
Example #5
0
        /// <summary>
        /// See <see cref="Kanji.Database.Dao.VocabDao.GetFilteredVocab"/>.
        /// Returns the results count.
        /// </summary>
        public long GetFilteredVocabCount(KanjiEntity kanji, string readingFilter,
            string meaningFilter)
        {
            List<DaoParameter> parameters = new List<DaoParameter>();
            string sqlFilterClauses = BuildVocabFilterClauses(parameters, kanji,
                readingFilter, meaningFilter);

            using (DaoConnection connection
                = DaoConnection.Open(DaoConnectionEnum.KanjiDatabase))
            {
                return (long)connection.QueryScalar(
                      "SELECT count(1) FROM " + SqlHelper.Table_Vocab + " v "
                    + sqlFilterClauses,
                    parameters.ToArray());
            }
        }
Example #6
0
        /// <summary>
        /// Retrieves and returns the collection of vocab matching the
        /// given filters.
        /// </summary>
        /// <param name="kanji">Kanji filter. Only vocab containing this
        /// kanji will be filtered in.</param>
        /// <param name="readingFilter">Reading filter. Only vocab containing
        /// this string in their kana or kanji reading will be filtered in.</param>
        /// <param name="meaningFilter">Meaning filter. Only vocab containing
        /// this string as part of at least one of their meaning entries will
        /// be filtered in.</param>
        /// <param name="isCommonFirst">Indicates if common vocab should be
        /// presented first. If false, results are sorted only by the length
        /// of their writing (asc or desc depending on the parameter)</param>
        /// <param name="isShortWritingFirst">Indicates if results should
        /// be sorted by ascending or descending writing length.
        /// If True, short readings come first. If False, long readings
        /// come first.</param>
        /// <returns>Vocab entities matching the filters.</returns>
        public IEnumerable<VocabEntity> GetFilteredVocab(KanjiEntity kanji,
            string readingFilter, string meaningFilter, bool isCommonFirst,
            bool isShortWritingFirst)
        {
            List<DaoParameter> parameters = new List<DaoParameter>();
            string sqlFilterClauses = BuildVocabFilterClauses(parameters, kanji,
                readingFilter, meaningFilter);

            string sortClause = "ORDER BY ";
            if (isCommonFirst)
            {
                sortClause += "v." + SqlHelper.Field_Vocab_IsCommon + " DESC,";
            }
            sortClause += "length(v." + SqlHelper.Field_Vocab_KanaWriting + ") "
                + (isShortWritingFirst ? "ASC" : "DESC");

            DaoConnection connection = null;
            DaoConnection srsConnection = null;
            try
            {
                connection = DaoConnection.Open(DaoConnectionEnum.KanjiDatabase);
                srsConnection = new DaoConnection(DaoConnectionEnum.SrsDatabase);
                srsConnection.OpenAsync();

                IEnumerable<NameValueCollection> vocabs = connection.Query(
                      "SELECT DISTINCT v.* FROM " + SqlHelper.Table_Vocab + " v "
                    + sqlFilterClauses
                    + sortClause,
                    parameters.ToArray());

                VocabBuilder vocabBuilder = new VocabBuilder();
                foreach (NameValueCollection nvcVocab in vocabs)
                {
                    VocabEntity vocab = vocabBuilder.BuildEntity(nvcVocab, null);
                    IncludeCategories(connection, vocab);
                    IncludeMeanings(connection, vocab);
                    IncludeKanji(connection, srsConnection, vocab);
                    IncludeSrsEntries(srsConnection, vocab);
                    IncludeVariants(connection, vocab);
                    yield return vocab;
                }
            }
            finally
            {
                if (connection != null)
                {
                    connection.Dispose();
                }
            }
        }
Example #7
0
        /// <summary>
        /// Retrieves and includes the SRS entries matching the given kanji and includes
        /// them in the entity.
        /// </summary>
        internal static void IncludeSrsEntries(DaoConnection connection, KanjiEntity kanji)
        {
            IEnumerable<NameValueCollection> nvcEntries = connection.Query(
                "SELECT * "
                + "FROM " + SqlHelper.Table_SrsEntry + " srs "
                + "WHERE srs." + SqlHelper.Field_SrsEntry_AssociatedKanji + "=@k",
                new DaoParameter("@k", kanji.Character));

            SrsEntryBuilder srsEntryBuilder = new SrsEntryBuilder();
            foreach (NameValueCollection nvcEntry in nvcEntries)
            {
                kanji.SrsEntries.Add(srsEntryBuilder.BuildEntity(nvcEntry, null));
            }
        }
Example #8
0
        /// <summary>
        /// Retrieves and includes the radicals of the given kanji in the entity.
        /// </summary>
        internal static void IncludeRadicals(DaoConnection connection, KanjiEntity kanji)
        {
            IEnumerable<NameValueCollection> nvcRadicals = connection.Query(
                        "SELECT * "
                      + "FROM " + SqlHelper.Table_Radical + " r "
                      + "JOIN " + SqlHelper.Table_Kanji_Radical + " kr "
                      + "ON (kr." + SqlHelper.Field_Kanji_Radical_RadicalId + "=r." + SqlHelper.Field_Radical_Id + ") "
                      + "WHERE kr." + SqlHelper.Field_Kanji_Radical_KanjiId + "=@kanjiId;",
                        new DaoParameter("@kanjiId", kanji.ID));

            RadicalBuilder radicalBuilder = new RadicalBuilder();
            foreach (NameValueCollection nvcRadical in nvcRadicals)
            {
                // For each meaning result : build a radical and set the associations.
                RadicalEntity radical = radicalBuilder.BuildEntity(nvcRadical, null);
                kanji.Radicals.Add(radical);
            }
        }
Example #9
0
        /// <summary>
        /// Retrieves and includes the meanings of the given kanji in the entity.
        /// </summary>
        internal static void IncludeKanjiMeanings(DaoConnection connection, KanjiEntity kanji)
        {
            IEnumerable<NameValueCollection> nvcMeanings = connection.Query(
                        "SELECT * "
                      + "FROM " + SqlHelper.Table_KanjiMeaning + " km "
                      + "WHERE km." + SqlHelper.Field_KanjiMeaning_KanjiId + "=@kanjiId "
                      + "AND km." + SqlHelper.Field_KanjiMeaning_Language + " IS NULL;",
                        new DaoParameter("@kanjiId", kanji.ID));

            KanjiMeaningBuilder meaningBuilder = new KanjiMeaningBuilder();
            foreach (NameValueCollection nvcMeaning in nvcMeanings)
            {
                // For each meaning result : build a meaning and set the associations.
                KanjiMeaning meaning = meaningBuilder.BuildEntity(nvcMeaning, null);
                meaning.Kanji = kanji;
                kanji.Meanings.Add(meaning);
            }
        }
Example #10
0
 public ExtendedKanji(KanjiEntity dbKanji)
 {
     DbKanji = dbKanji;
     RadicalStore.Instance.IssueWhenLoaded(OnRadicalsLoaded);
 }
 public void LoadFromKanji(KanjiEntity k)
 {
     Reference.LoadFromKanji(k);
     RaisePropertyChanged("Meanings");
     RaisePropertyChanged("Readings");
 }