/// <summary> /// Recursive search for right ss - sharp s permutations /// </summary> private WordEntry SpellSharps(ref string @base, int nPos, int n, int repNum, ref SpellCheckResultType info, out string root) { var pos = @base.IndexOfOrdinal("ss", nPos); if (pos >= 0 && n < MaxSharps) { var baseBuilder = StringBuilderPool.Get(@base, @base.Length); baseBuilder[pos] = 'ß'; baseBuilder.Remove(pos + 1, 1); @base = baseBuilder.ToString(); var h = SpellSharps(ref @base, pos + 1, n + 1, repNum + 1, ref info, out root); if (h != null) { return(h); } baseBuilder.Clear(); baseBuilder.Append(@base); baseBuilder[pos] = 's'; baseBuilder.Insert(pos + 1, 's'); @base = StringBuilderPool.GetStringAndReturn(baseBuilder); h = SpellSharps(ref @base, pos + 2, n + 1, repNum, ref info, out root); if (h != null) { return(h); } } else if (repNum > 0) { return(CheckWord(@base, ref info, out root)); } root = null; return(null); }
public string ReadLine() { if (!hasCheckedForPreamble) { ReadPreamble(); } var builder = StringBuilderPool.Get(); while (ReadNextChars()) { if (ProcessCharsForLine(builder)) { break; } } if (charBuffer == null && builder.Length == 0) { return(null); } return(ProcessLine(StringBuilderPool.GetStringAndReturn(builder))); }
public async Task <string> ReadLineAsync() { if (!hasCheckedForPreamble) { await ReadPreambleAsync().ConfigureAwait(false); } var builder = StringBuilderPool.Get(); while (await ReadNextCharsAsync().ConfigureAwait(false)) { if (ProcessCharsForLine(builder)) { break; } } if (charBuffer == null && builder.Length == 0) { return(null); } return(ProcessLine(StringBuilderPool.GetStringAndReturn(builder))); }
private static string ReverseCondition(string conditionText) { if (string.IsNullOrEmpty(conditionText)) { return(conditionText); } var chars = StringBuilderPool.Get(conditionText); chars.Reverse(); var neg = false; var lastIndex = chars.Length - 1; for (int k = lastIndex; k >= 0; k--) { switch (chars[k]) { case '[': if (neg) { if (k < lastIndex) { chars[k + 1] = '['; } } else { chars[k] = ']'; } break; case ']': chars[k] = '['; if (neg && k < lastIndex) { chars[k + 1] = '^'; } neg = false; break; case '^': if (k < lastIndex) { if (chars[k + 1] == ']') { neg = true; } else { chars[k + 1] = chars[k]; } } break; default: if (neg && k < lastIndex) { chars[k + 1] = chars[k]; } break; } } return(StringBuilderPool.GetStringAndReturn(chars)); }
private bool TryParseAffixIntoList <TEntry>(string parameterText, ref List <AffixEntryGroup.Builder <TEntry> > groups) where TEntry : AffixEntry, new() { if (groups == null) { groups = new List <AffixEntryGroup.Builder <TEntry> >(); } var lineMatch = AffixLineRegex.Match(parameterText); if (!lineMatch.Success) { Builder.LogWarning("Failed to parse affix line: " + parameterText); return(false); } var lineMatchGroups = lineMatch.Groups; FlagValue characterFlag; if (!TryParseFlag(lineMatchGroups[1].Value, out characterFlag)) { Builder.LogWarning($"Failed to parse affix flag for {lineMatchGroups[1].Value} from: {parameterText}"); return(false); } var affixGroup = groups.FindLast(g => g.AFlag == characterFlag); var contClass = FlagSet.Empty; if (lineMatchGroups[2].Success && lineMatchGroups[3].Success) { if (affixGroup != null) { Builder.LogWarning($"Duplicate affix group definition for {affixGroup.AFlag} from: {parameterText}"); return(false); } var options = AffixEntryOptions.None; if (lineMatchGroups[2].Value.StartsWith('Y')) { options |= AffixEntryOptions.CrossProduct; } if (Builder.IsAliasM) { options |= AffixEntryOptions.AliasM; } if (Builder.IsAliasF) { options |= AffixEntryOptions.AliasF; } int expectedEntryCount; IntEx.TryParseInvariant(lineMatchGroups[3].Value, out expectedEntryCount); affixGroup = new AffixEntryGroup.Builder <TEntry> { AFlag = characterFlag, Options = options, Entries = new List <TEntry>(expectedEntryCount) }; groups.Add(affixGroup); return(true); } else if (lineMatchGroups[4].Success && lineMatchGroups[5].Success && lineMatchGroups[6].Success) { // piece 3 - is string to strip or 0 for null var strip = lineMatchGroups[4].Value; if (strip == "0") { strip = string.Empty; } else if (EnumEx.HasFlag(Builder.Options, AffixConfigOptions.ComplexPrefixes)) { strip = strip.Reverse(); } // piece 4 - is affix string or 0 for null var affixInput = lineMatchGroups[5].Value; var affixSlashIndex = affixInput.IndexOf('/'); StringBuilder affixText; if (affixSlashIndex >= 0) { var slashPartOffset = affixSlashIndex + 1; var slashPartLength = affixInput.Length - slashPartOffset; affixText = StringBuilderPool.Get(affixInput, 0, affixSlashIndex); if (Builder.IsAliasF) { int aliasNumber; if (IntEx.TryParseInvariant(affixInput.Subslice(slashPartOffset, slashPartLength), out aliasNumber) && aliasNumber > 0 && aliasNumber <= Builder.AliasF.Count) { contClass = Builder.AliasF[aliasNumber - 1]; } else { Builder.LogWarning($"Failed to parse contclasses from : {parameterText}"); return(false); } } else { contClass = ParseFlags(affixInput.Subslice(slashPartOffset, slashPartLength)); } } else { affixText = StringBuilderPool.Get(affixInput); } if (Builder.IgnoredChars != null && Builder.IgnoredChars.HasItems) { affixText.RemoveChars(Builder.IgnoredChars); } if (EnumEx.HasFlag(Builder.Options, AffixConfigOptions.ComplexPrefixes)) { affixText.Reverse(); } if (affixText.Length == 1 && affixText[0] == '0') { affixText.Clear(); } // piece 5 - is the conditions descriptions var conditionText = lineMatchGroups[6].Value; if (EnumEx.HasFlag(Builder.Options, AffixConfigOptions.ComplexPrefixes)) { conditionText = ReverseCondition(conditionText); } var conditions = CharacterCondition.Parse(conditionText); if (!string.IsNullOrEmpty(strip) && !conditions.AllowsAnySingleCharacter) { bool isRedundant; if (typeof(TEntry) == typeof(PrefixEntry)) { isRedundant = RedundantConditionPrefix(strip, conditions); } else if (typeof(TEntry) == typeof(SuffixEntry)) { isRedundant = RedundantConditionSuffix(strip, conditions); } else { throw new NotSupportedException(); } if (isRedundant) { conditions = CharacterConditionGroup.AllowAnySingleCharacter; } } // piece 6 MorphSet morph; if (lineMatchGroups[7].Success) { var morphAffixText = lineMatchGroups[7].Value; if (Builder.IsAliasM) { int morphNumber; if (IntEx.TryParseInvariant(morphAffixText, out morphNumber) && morphNumber > 0 && morphNumber <= Builder.AliasM.Count) { morph = Builder.AliasM[morphNumber - 1]; } else { Builder.LogWarning($"Failed to parse morph {morphAffixText} from: {parameterText}"); return(false); } } else { if (EnumEx.HasFlag(Builder.Options, AffixConfigOptions.ComplexPrefixes)) { morphAffixText = morphAffixText.Reverse(); } morph = Builder.Dedup(MorphSet.TakeArray(Builder.DedupInPlace(morphAffixText.SplitOnTabOrSpace()))); } } else { morph = MorphSet.Empty; } if (affixGroup == null) { affixGroup = new AffixEntryGroup.Builder <TEntry> { AFlag = characterFlag, Options = AffixEntryOptions.None, Entries = new List <TEntry>() }; } if (!Builder.HasContClass && contClass.HasItems) { Builder.HasContClass = true; } affixGroup.Entries.Add(AffixEntry.Create <TEntry>( Builder.Dedup(strip), Builder.Dedup(StringBuilderPool.GetStringAndReturn(affixText)), Builder.Dedup(conditions), morph, contClass)); return(true); } else { Builder.LogWarning("Affix line not fully parsed: " + parameterText); return(false); } }