public IEnumerable <JGram.Entry> Lookup(string key) { int limit = 50; var(start, end) = index.EqualRange(key, kvp => kvp.Key); var outOfBoundLimit = (limit - (end - start)) / 2; start = Math.Max(0, start - outOfBoundLimit); end = Math.Min(entries.Count, end + outOfBoundLimit); var mid = (start + end) / 2; var resultEntries = EnumerableExt.Range(start, end - start) .OrderBy(i => Math.Abs(i - mid)) .Select(i => index[i]) .Select(indexEntry => { var indexKey = indexEntry.Key; var entryKey = indexEntry.Value; var(entry, id) = entries.BinarySearch(entryKey, e => e.Id); return((indexKey, entry).SomeWhen(_ => id != -1)); }) .Values() .OrderByDescending(r => CommonPrefixLength(r.indexKey, key)) .Where(r => CommonPrefixLength(r.indexKey, key) != 0) .Select(r => r.entry); return(EnumerableExt.DistinctBy(resultEntries, entry => entry.Id)); }
public static JMDictParser Create(Stream stream) { DateTime?versionDate = null; var undoEntityExpansionDictionary = new DualDictionary <string, string>(); var xmlReader = new XmlTextReader(stream); xmlReader.EntityHandling = EntityHandling.ExpandCharEntities; xmlReader.DtdProcessing = DtdProcessing.Parse; xmlReader.XmlResolver = null; while (xmlReader.Read()) { if (xmlReader.NodeType == XmlNodeType.DocumentType) { undoEntityExpansionDictionary = new DualDictionary <string, string>( EnumerableExt.DistinctBy( XmlEntities.ParseJMDictEntities(xmlReader.Value), kvp => kvp.Key)); } if (xmlReader.NodeType == XmlNodeType.Comment) { var commentText = xmlReader.Value.Trim(); if (commentText.StartsWith("JMdict created:", StringComparison.Ordinal)) { var generationDate = commentText.Split(':').ElementAtOrDefault(1)?.Trim(); if (DateTime.TryParseExact(generationDate, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var date)) { versionDate = date; } else { versionDate = null; } } } if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "JMdict") { break; } } return(new JMDictParser(versionDate, undoEntityExpansionDictionary, xmlReader)); }
public Option <KanjiLookupResult, Error> SelectRadicals( string query, string sort, string select = null, string deselect = null) { // validation and normalization query = query ?? ""; var sortingCriteriaIndexOpt = sort == null ? Option.Some <int>(0) : radicalLookup.SortingCriteria .FindIndexOrNone(criterion => criterion.Description == sort); if (!sortingCriteriaIndexOpt.HasValue) { return(Option.None <KanjiLookupResult, Error>( new Error(ErrorCodes.InvalidInput, "Invalid sorting criterion", new[] { nameof(sort), sort }))); } var sortingCriteriaIndex = sortingCriteriaIndexOpt.ValueOrFailure(); // get corresponding radicals var radicalSearchResults = radicalSearcher.Search(query); var usedRadicals = EnumerableExt.DistinctBy(radicalSearchResults, r => r.Text) .Select(r => new KeyValuePair <string, string>(r.Text, r.Radical.ToString())); // select if (select != null) { query += " " + select; } // unselect if (deselect != null) { foreach (var kvp in usedRadicals.Where(x => x.Value == deselect)) { var name = kvp.Key; query = query.Replace(name, ""); } } query = query.Trim(); // search again, with the new radicals radicalSearchResults = radicalSearcher.Search(query); var radicals = radicalSearchResults .Select(result => result.Radical) .ToList(); if (radicals.Count == 0) { return(Option.Some <KanjiLookupResult, Error>(new KanjiLookupResult ( newQuery: query, kanji: Array.Empty <string>(), radicals: radicalLookup.AllRadicals .Select(r => new RadicalState(r.ToString(), isAvailable: true, isSelected: false)) .ToList() ))); } var selectionResult = radicalLookup.SelectRadical(radicals, sortingCriteriaIndex); var usedRadicalsSet = new HashSet <CodePoint>(radicalSearchResults.Select(r => r.Radical)); return(Option.Some <KanjiLookupResult, Error>(new KanjiLookupResult ( newQuery: query, kanji: selectionResult.Kanji .Select(k => k.ToString()) .ToList(), radicals: selectionResult.PossibleRadicals .Select(k => new RadicalState(k.Key.ToString(), k.Value || usedRadicalsSet.Contains(k.Key), usedRadicalsSet.Contains(k.Key))) .ToList() ))); }