void ApplySimultaneous(PhoneticShape input, List <Subrule> subrules) { foreach (Subrule sr in subrules) { // first find all segments which match the LHS List <Match> matches = new List <Match>(); PhoneticShapeNode node = input.First; Match match; while (FindNextMatchLHS(node, Direction.RIGHT, out match)) { // check each candidate match against the subrule's environment IList <PhoneticShapeNode> nodes = match.EntireMatch; VariableValues instantiatedVars = match.VariableValues; if (m_lhs.Count == 0 ? sr.MatchEnvEmpty(nodes[0], Direction.RIGHT, ModeType.SYNTHESIS, instantiatedVars) : sr.MatchEnvNonempty(nodes, Direction.RIGHT, ModeType.SYNTHESIS, instantiatedVars)) { matches.Add(match); node = nodes[nodes.Count - 1].Next; } else { node = nodes[0].Next; } } // then apply changes foreach (Match m in matches) { sr.ApplyRHS(Direction.RIGHT, m.EntireMatch, m.VariableValues); } } }
/// <summary> /// Searches for the lexical entry that matches the specified shape. /// </summary> /// <param name="shape">The shape.</param> /// <returns>The matching lexical entries.</returns> public IEnumerable <LexEntry.RootAllomorph> SearchEntries(PhoneticShape shape) { foreach (SegmentDefinitionTrie <LexEntry.RootAllomorph> .Match match in m_entryTrie.Search(shape)) { yield return(match.Value); } }
void ApplyIterative(PhoneticShape input, Direction dir, List <Subrule> subrules) { Match match; PhoneticShapeNode node = input.GetFirst(dir); // iterate thru each LHS match while (FindNextMatchLHS(node, dir, out match)) { IList <PhoneticShapeNode> nodes = match.EntireMatch; VariableValues instantiatedVars = match.VariableValues; bool matched = false; // check each subrule's environment foreach (Subrule sr in subrules) { if (m_lhs.Count == 0 ? sr.MatchEnvEmpty(nodes[0], dir, ModeType.SYNTHESIS, instantiatedVars) : sr.MatchEnvNonempty(nodes, dir, ModeType.SYNTHESIS, instantiatedVars)) { sr.ApplyRHS(dir, nodes, instantiatedVars); matched = true; break; } } if (matched) { node = nodes[nodes.Count - 1].GetNext(dir); } else { node = nodes[0].GetNext(dir); } } }
void Untruncate(PhoneticPattern lhs, PhoneticShape output, bool optional, VariableValues instantiatedVars) { // create segments from the LHS partition pattern and append them to the output foreach (PhoneticPatternNode node in lhs) { switch (node.Type) { case PhoneticPatternNode.NodeType.SIMP_CTXT: SimpleContext ctxt = node as SimpleContext; Segment newSeg = ctxt.UnapplyDeletion(instantiatedVars); newSeg.IsOptional = optional; output.Add(newSeg); break; case PhoneticPatternNode.NodeType.PATTERN: NestedPhoneticPattern nestedPattern = node as NestedPhoneticPattern; // untruncate nested partitions the maximum number of times it can occur, // marking any segments that occur after the minimum number of occurrences // as optional for (int j = 0; j < nestedPattern.MaxOccur; j++) { Untruncate(nestedPattern.Pattern, output, j >= nestedPattern.MinOccur, instantiatedVars); } break; case PhoneticPatternNode.NodeType.BDRY_CTXT: // skip boundaries break; } } }
/// <summary> /// Initializes a new instance of the <see cref="WordSynthesis"/> class. /// </summary> /// <param name="rootAllomorph">The root allomorph.</param> /// <param name="nonHead">The non-head synthesis.</param> /// <param name="rzFeatures">The realizational features.</param> /// <param name="mrules">The morphological rules to apply.</param> /// <param name="curTrace">The current trace record.</param> internal WordSynthesis(LexEntry.RootAllomorph rootAllomorph, WordSynthesis nonHead, FeatureValues rzFeatures, IEnumerable <MorphologicalRule> mrules, Trace curTrace) { m_root = (LexEntry)rootAllomorph.Morpheme; m_mprFeatures = m_root.MPRFeatures != null?m_root.MPRFeatures.Clone() : new MPRFeatureSet(); m_headFeatures = m_root.HeadFeatures != null?m_root.HeadFeatures.Clone() : new FeatureValues(); m_footFeatures = m_root.FootFeatures != null?m_root.FootFeatures.Clone() : new FeatureValues(); m_pos = m_root.POS; m_stratum = m_root.Stratum; m_nonHead = nonHead; m_morphs = new Morphs(); Morph morph = new Morph(rootAllomorph); morph.Shape.AddMany(rootAllomorph.Shape.Segments); m_morphs.Add(morph); m_shape = new PhoneticShape(); m_shape.Add(new Margin(Direction.LEFT)); m_shape.AddPartition(rootAllomorph.Shape.Segments, morph.Partition); m_shape.Add(new Margin(Direction.RIGHT)); m_obligHeadFeatures = new HCObjectSet <Feature>(); m_mrules = new List <MorphologicalRule>(mrules); m_rzFeatures = rzFeatures; m_curTrace = curTrace; m_mrulesApplied = new Dictionary <MorphologicalRule, int>(); }
/// <summary> /// Generates a string representation of the specified phonetic shape. /// </summary> /// <param name="shape">The phonetic shape.</param> /// <param name="mode">The mode.</param> /// <param name="includeBdry">if <c>true</c> boundary markers will be included in the /// string representation.</param> /// <returns>The string representation.</returns> public string ToString(PhoneticShape shape, ModeType mode, bool includeBdry) { StringBuilder sb = new StringBuilder(); foreach (PhoneticShapeNode node in shape) { switch (node.Type) { case PhoneticShapeNode.NodeType.SEGMENT: Segment seg = node as Segment; IList <SegmentDefinition> segDefs = GetMatchingSegmentDefinitions(seg, mode); if (segDefs.Count > 0) { sb.Append(segDefs[0].StrRep); } break; case PhoneticShapeNode.NodeType.BOUNDARY: if (includeBdry) { Boundary bdry = node as Boundary; sb.Append(bdry.BoundaryDefinition.StrRep); } break; } } return(sb.ToString()); }
/// <summary> /// Applies the rule to the specified word synthesis. /// </summary> /// <param name="input">The word synthesis.</param> public override void Apply(WordSynthesis input) { PhonologicalRuleSynthesisTrace trace = null; if (TraceSynthesis) { // create phonological rule synthesis trace record trace = new PhonologicalRuleSynthesisTrace(this, input.Clone()); input.CurrentTrace.AddChild(trace); } // only try to apply applicable subrules List <Subrule> subrules = new List <Subrule>(); foreach (Subrule sr in m_subrules) { if (sr.IsApplicable(input)) { subrules.Add(sr); } } if (subrules.Count > 0) { // set all segments to clean PhoneticShape pshape = input.Shape; foreach (PhoneticShapeNode node in pshape) { if (node.Type == PhoneticShapeNode.NodeType.SEGMENT) { (node as Segment).IsClean = true; } } switch (m_multApplication) { case MultAppOrder.SIMULTANEOUS: ApplySimultaneous(input.Shape, subrules); break; case MultAppOrder.LR_ITERATIVE: ApplyIterative(input.Shape, Direction.RIGHT, subrules); break; case MultAppOrder.RL_ITERATIVE: ApplyIterative(input.Shape, Direction.LEFT, subrules); break; } } // add output to phonological rule trace record if (trace != null) { trace.Output = input.Clone(); } }
/// <summary> /// Initializes a new instance of the <see cref="WordAnalysis"/> class. /// </summary> /// <param name="shape">The shape.</param> /// <param name="curTrace">The current trace record.</param> internal WordAnalysis(PhoneticShape shape, Stratum stratum, Trace curTrace) { m_shape = shape; m_pos = new HCObjectSet <PartOfSpeech>(); m_mrules = new List <MorphologicalRule>(); m_mrulesUnapplied = new Dictionary <MorphologicalRule, int>(); m_rzFeatures = new FeatureValues(); m_stratum = stratum; m_curTrace = curTrace; }
/// <summary> /// Determines whether the specified word matches the specified phonetic shape. /// All unused IPA modifiers in the word are ignored when attempting to match /// the phonetic shape. /// </summary> /// <param name="word">The word.</param> /// <param name="shape">The phonetic shape.</param> /// <returns> /// <c>true</c> if the word matches the shape, otherwise <c>false</c>. /// </returns> public override bool IsMatch(string word, PhoneticShape shape) { string tword; if (!StripUnusedChars(word, out tword)) { return(false); } return(base.IsMatch(tword, shape)); }
PhoneticShape UnapplyRHS(Match match) { PhoneticShape output = new PhoneticShape(); output.Add(new Margin(Direction.LEFT)); // iterate thru LHS partitions, copying the matching partition from the // input to the output for (int i = 0; i < m_transform.PartitionCount; i++) { m_transform.Unapply(match, i, output); } output.Add(new Margin(Direction.RIGHT)); return(output); }
/// <summary> /// Copy constructor. /// </summary> /// <param name="wa">The word analysis.</param> public WordAnalysis(WordAnalysis wa) { m_shape = wa.m_shape.Clone(); m_pos = new HCObjectSet <PartOfSpeech>(wa.m_pos); m_rootAllomorph = wa.m_rootAllomorph; if (wa.m_nonHead != null) { m_nonHead = wa.m_nonHead.Clone(); } m_mrules = new List <MorphologicalRule>(wa.m_mrules); m_mrulesUnapplied = new Dictionary <MorphologicalRule, int>(wa.m_mrulesUnapplied); m_rzFeatures = wa.m_rzFeatures.Clone(); m_curTrace = wa.m_curTrace; m_stratum = wa.m_stratum; }
/// <summary> /// Unapplies this subrule to the input word analysis. /// </summary> /// <param name="input">The input word analysis.</param> /// <param name="output">The output word analyses.</param> /// <returns><c>true</c> if the subrule was successfully unapplied, otherwise <c>false</c></returns> public bool Unapply(WordAnalysis input, out ICollection <WordAnalysis> output) { VariableValues instantiatedVars = new VariableValues(m_alphaVars); IList <Match> matches; m_transform.RHSTemplate.IsMatch(input.Shape.First, Direction.RIGHT, ModeType.ANALYSIS, instantiatedVars, out matches); List <WordAnalysis> outputList = new List <WordAnalysis>(); output = outputList; foreach (Match match in matches) { PhoneticShape shape = UnapplyRHS(match); if (shape.Count > 2) { // check to see if this is a duplicate of another output analysis, this is not strictly necessary, but // it helps to reduce the search space bool add = true; for (int i = 0; i < output.Count; i++) { if (shape.Duplicates(outputList[i].Shape)) { if (shape.Count > outputList[i].Shape.Count) { // if this is a duplicate and it is longer, then use this analysis and remove the previous one outputList.RemoveAt(i); } else { // if it is shorter, then do not add it to the output list add = false; } break; } } if (add) { WordAnalysis wa = input.Clone(); wa.Shape = shape; output.Add(wa); } } } return(outputList.Count > 0); }
void UnapplyRHS(Match match, out PhoneticShape headShape, out PhoneticShape nonHeadShape) { headShape = new PhoneticShape(); headShape.Add(new Margin(Direction.LEFT)); nonHeadShape = new PhoneticShape(); nonHeadShape.Add(new Margin(Direction.LEFT)); // iterate thru LHS partitions, copying the matching partition from the // input to the output for (int i = 0; i < m_transform.PartitionCount; i++) { PhoneticShape curShape = i < m_firstNonHeadPartition ? headShape : nonHeadShape; m_transform.Unapply(match, i, curShape); } headShape.Add(new Margin(Direction.RIGHT)); nonHeadShape.Add(new Margin(Direction.RIGHT)); }
/// <summary> /// Unapplies this subrule to specified input phonetic shape. /// </summary> /// <param name="input">The input phonetic shape.</param> public void Unapply(PhoneticShape input) { if (Type == ChangeType.NARROW) { int i = 0; // because deletion rules are self-opaquing it is unclear how many segments // could have been deleted during synthesis, so we unapply deletion rules // multiple times. Unfortunately, this could create a situation where the // deletion rule is unapplied infinitely, so we put an upper limit on the // number of times a deletion rule can unapply. while (i <= m_rule.Morpher.DelReapplications && UnapplyNarrow(input)) { i++; } } else { Direction dir = Direction.LEFT; switch (m_rule.m_multApplication) { case MultAppOrder.LR_ITERATIVE: case MultAppOrder.SIMULTANEOUS: // simultaneous subrules could be unapplied left-to-right or // right-to-left, we arbitrarily choose left-to-right dir = Direction.LEFT; break; case MultAppOrder.RL_ITERATIVE: dir = Direction.RIGHT; break; } // only simultaneous subrules can be self-opaquing if (IsSelfOpaquing) { // unapply the subrule until it no longer makes a change while (UnapplyIterative(input, dir)) { } } else { UnapplyIterative(input, dir); } } }
bool UnapplyIterative(PhoneticShape input, Direction dir) { bool unapplied = false; PhoneticShapeNode node = input.GetFirst(dir); Match match; // iterate thru all matches while (FindNextMatchRHS(node, dir, out match)) { // unapply the subrule IList <PhoneticShapeNode> nodes = match.EntireMatch; UnapplyRHS(dir, nodes, match.VariableValues); unapplied = true; node = nodes[nodes.Count - 1].GetNext(dir); } return(unapplied); }
bool ProcessIterative(PhoneticShape input, Direction dir, PhoneticPattern ptemp, ModeType mode) { bool reordered = false; PhoneticShapeNode node = input.GetFirst(dir); Match match; // iterate thru each match while (FindNextMatch(node, dir, ptemp, mode, out match)) { // reorder the matching segments Reorder(dir, match); reordered = true; IList <PhoneticShapeNode> nodes = match.EntireMatch; node = nodes[nodes.Count - 1].GetNext(dir); } return(reordered); }
bool UnapplyNarrow(PhoneticShape input) { List <Match> matches = new List <Match>(); PhoneticShapeNode node = input.First; Match match; // deletion subrules are always treated like simultaneous subrules during unapplication while (FindNextMatchRHS(node, Direction.RIGHT, out match)) { matches.Add(match); node = match.EntireMatch[0].Next; } foreach (Match m in matches) { PhoneticShapeNode cur = m.EntireMatch[m.EntireMatch.Count - 1]; foreach (PhoneticPatternNode lhsNode in m_rule.m_lhs) { if (lhsNode.Type != PhoneticPatternNode.NodeType.SIMP_CTXT) { continue; } SimpleContext ctxt = lhsNode as SimpleContext; Segment newSeg = ctxt.UnapplyDeletion(m.VariableValues); // mark the undeleted segment as optional newSeg.IsOptional = true; cur.Insert(newSeg, Direction.RIGHT); cur = newSeg; } if (m_analysisTarget.Count > 0) { foreach (PhoneticShapeNode matchNode in m.EntireMatch) { matchNode.IsOptional = true; } } } return(matches.Count > 0); }
/// <summary> /// Copy constructor. /// </summary> /// <param name="ws">The word synthesis.</param> public WordSynthesis(WordSynthesis ws) { m_root = ws.m_root; if (ws.m_nonHead != null) { m_nonHead = ws.m_nonHead.Clone(); } m_shape = ws.m_shape.Clone(); m_morphs = ws.m_morphs.Clone(); m_pos = ws.m_pos; m_mprFeatures = ws.m_mprFeatures.Clone(); m_headFeatures = ws.m_headFeatures.Clone(); m_footFeatures = ws.m_footFeatures.Clone(); m_obligHeadFeatures = new HCObjectSet <Feature>(ws.m_obligHeadFeatures); m_mrules = new List <MorphologicalRule>(ws.m_mrules); m_curRuleIndex = ws.m_curRuleIndex; m_rzFeatures = ws.m_rzFeatures.Clone(); m_curTrace = ws.m_curTrace; m_stratum = ws.m_stratum; m_mrulesApplied = new Dictionary <MorphologicalRule, int>(ws.m_mrulesApplied); }
/// <summary> /// Converts the specified string to a phonetic shape. It matches the longest possible segment /// first. /// </summary> /// <param name="str">The string.</param> /// <param name="mode">The mode.</param> /// <returns>The phonetic shape, <c>null</c> if the string contains invalid segments.</returns> public PhoneticShape ToPhoneticShape(string str, ModeType mode) { PhoneticShape ps = new PhoneticShape(); int i = 0; ps.Add(new Margin(Direction.LEFT)); while (i < str.Length) { bool match = false; for (int j = str.Length - i; j > 0; j--) { string s = str.Substring(i, j); PhoneticShapeNode node = GetPhoneticShapeNode(s, mode); if (node != null) { try { ps.Add(node); } catch (InvalidOperationException) { return(null); } i += j; match = true; break; } } if (!match) { return(null); } } ps.Add(new Margin(Direction.RIGHT)); return(ps); }
/// <summary> /// Unapplies this transform to the specified partition in the specified match. /// </summary> /// <param name="match">The match.</param> /// <param name="partition">The partition.</param> /// <param name="output">The output.</param> public void Unapply(Match match, int partition, PhoneticShape output) { IList <PhoneticShapeNode> nodes = match.GetPartition(partition); if (nodes != null && nodes.Count > 0) { SimpleContext ctxt; if (!m_modifyFromCtxts.TryGetValue(partition, out ctxt)) { ctxt = null; } foreach (PhoneticShapeNode node in nodes) { switch (node.Type) { case PhoneticShapeNode.NodeType.SEGMENT: Segment newSeg = new Segment(node as Segment); // if there is a modify-from context on this partition, unapply it if (ctxt != null) { ctxt.Unapply(newSeg, match.VariableValues); } output.Add(newSeg); break; case PhoneticShapeNode.NodeType.BOUNDARY: output.Add(node.Clone()); break; } } } else { // untruncate a partition Untruncate(m_lhs[partition], output, false, match.VariableValues); } }
/// <summary> /// Initializes a new instance of the <see cref="RootTrace"/> class. /// </summary> /// <param name="inputWord">The input word.</param> /// <param name="inputShape">The input shape.</param> internal WordAnalysisTrace(string inputWord, PhoneticShape inputShape) { m_inputWord = inputWord; m_inputShape = inputShape; }
/// <summary> /// Copy constructor. /// </summary> /// <param name="morph">The morph.</param> public Morph(Morph morph) { m_partition = morph.m_partition; m_shape = morph.m_shape.Clone(); m_allomorph = morph.m_allomorph; }
/// <summary> /// Initializes a new instance of the <see cref="Morph"/> class. /// </summary> /// <param name="allomorph">The allomorph.</param> public Morph(Allomorph allomorph) { m_allomorph = allomorph; m_shape = new PhoneticShape(); }
/// <summary> /// Initializes a new instance of the <see cref="InsertSegments"/> class. /// </summary> /// <param name="pshape">The phonetic shape.</param> public InsertSegments(PhoneticShape pshape) { m_pshape = pshape; }
/// <summary> /// Converts the specified phonetic shape to a valid regular expression string. Regular expressions /// formatted for display purposes are NOT guaranteed to compile. /// </summary> /// <param name="shape">The phonetic shape.</param> /// <param name="mode">The mode.</param> /// <param name="displayFormat">if <c>true</c> the result will be formatted for display, otherwise /// it will be formatted for compilation.</param> /// <returns>The regular expression string.</returns> public string ToRegexString(PhoneticShape shape, ModeType mode, bool displayFormat) { StringBuilder sb = new StringBuilder(); foreach (PhoneticShapeNode node in shape) { switch (node.Type) { case PhoneticShapeNode.NodeType.SEGMENT: Segment seg = node as Segment; IList <SegmentDefinition> segDefs = GetMatchingSegmentDefinitions(seg, mode); if (segDefs.Count > 0) { if (segDefs.Count > 1) { sb.Append(displayFormat ? "[" : "("); } for (int i = 0; i < segDefs.Count; i++) { if (segDefs[i].StrRep.Length > 1) { sb.Append("("); } if (displayFormat) { sb.Append(segDefs[i].StrRep); } else { sb.Append(Regex.Escape(segDefs[i].StrRep)); } if (segDefs[i].StrRep.Length > 1) { sb.Append(")"); } if (i < segDefs.Count - 1 && !displayFormat) { sb.Append("|"); } } if (segDefs.Count > 1) { sb.Append(displayFormat ? "]" : ")"); } if (seg.IsOptional) { sb.Append("?"); } } break; case PhoneticShapeNode.NodeType.BOUNDARY: Boundary bdry = node as Boundary; if (bdry.BoundaryDefinition.StrRep.Length > 1) { sb.Append("("); } if (displayFormat) { sb.Append(bdry.BoundaryDefinition.StrRep); } else { sb.Append(Regex.Escape(bdry.BoundaryDefinition.StrRep)); } if (bdry.BoundaryDefinition.StrRep.Length > 1) { sb.Append(")"); } sb.Append("?"); break; case PhoneticShapeNode.NodeType.MARGIN: if (!displayFormat) { Margin margin = node as Margin; sb.Append(margin.MarginType == Direction.LEFT ? "^" : "$"); } break; } } return(sb.ToString()); }
/// <summary> /// Initializes a new instance of the <see cref="LexLookupTrace"/> class. /// </summary> /// <param name="stratum">The stratum.</param> /// <param name="shape">The shape.</param> internal LexLookupTrace(Stratum stratum, PhoneticShape shape) { m_stratum = stratum; m_shape = shape; }
public IEnumerable <Match> SearchPartial(PhoneticShape shape) { return(new Set <Match>(m_root.Search(shape.GetFirst(m_dir), m_dir, true))); }
/// <summary> /// Adds the specified lexical entry. /// </summary> /// <param name="entry">The lexical entry.</param> public void Add(PhoneticShape shape, T value) { m_root.Add(shape.GetFirst(m_dir), value, m_dir); m_numValues++; }
/// <summary> /// Does the real work of morphing the specified word. /// </summary> /// <param name="word">The word.</param> /// <param name="prev">The previous word.</param> /// <param name="next">The next word.</param> /// <param name="trace">The trace.</param> /// <returns>All valid word synthesis records.</returns> ICollection <WordSynthesis> MorphAndLookupToken(string word, string prev, string next, out WordAnalysisTrace trace, string[] selectTraceMorphs) { // convert the word to its phonetic shape PhoneticShape input = SurfaceStratum.CharacterDefinitionTable.ToPhoneticShape(word, ModeType.ANALYSIS); // if word contains invalid segments, the char def table will return null if (input == null) { MorphException me = new MorphException(MorphException.MorphErrorType.INVALID_SHAPE, this, string.Format(HCStrings.kstidInvalidWord, word, SurfaceStratum.CharacterDefinitionTable.ID)); me.Data["shape"] = word; me.Data["charDefTable"] = SurfaceStratum.CharacterDefinitionTable.ID; throw me; } // create the root of the trace tree trace = new WordAnalysisTrace(word, input.Clone()); Set <WordSynthesis> candidates = new Set <WordSynthesis>(); Set <WordAnalysis> inAnalysis = new Set <WordAnalysis>(); Set <WordAnalysis> outAnalysis = new Set <WordAnalysis>(); inAnalysis.Add(new WordAnalysis(input, SurfaceStratum, trace)); // Unapply rules for (int i = m_strata.Count - 1; i >= 0; i--) { outAnalysis.Clear(); foreach (WordAnalysis wa in inAnalysis) { if (m_traceStrataAnalysis) { // create the stratum analysis input trace record StratumAnalysisTrace stratumTrace = new StratumAnalysisTrace(m_strata[i], true, wa.Clone()); wa.CurrentTrace.AddChild(stratumTrace); } foreach (WordAnalysis outWa in m_strata[i].Unapply(wa, candidates, selectTraceMorphs)) { // promote each analysis to the next stratum if (i != 0) { outWa.Stratum = m_strata[i - 1]; } if (m_traceStrataAnalysis) { // create the stratum analysis output trace record for the output word synthesis outWa.CurrentTrace.AddChild(new StratumAnalysisTrace(m_strata[i], false, outWa.Clone())); } outAnalysis.Add(outWa); } } inAnalysis.Clear(); inAnalysis.AddMany(outAnalysis); } Set <WordSynthesis> allValidSyntheses = new Set <WordSynthesis>(); // Apply rules for each candidate entry foreach (WordSynthesis candidate in candidates) { Set <WordSynthesis> inSynthesis = new Set <WordSynthesis>(); Set <WordSynthesis> outSynthesis = new Set <WordSynthesis>(); for (int i = 0; i < m_strata.Count; i++) { // start applying at the stratum that this lex entry belongs to if (m_strata[i] == candidate.Root.Stratum) { inSynthesis.Add(candidate); } outSynthesis.Clear(); foreach (WordSynthesis cur in inSynthesis) { if (m_traceStrataSynthesis) { // create the stratum synthesis input trace record StratumSynthesisTrace stratumTrace = new StratumSynthesisTrace(m_strata[i], true, cur.Clone()); cur.CurrentTrace.AddChild(stratumTrace); } foreach (WordSynthesis outWs in m_strata[i].Apply(cur)) { // promote the word synthesis to the next stratum if (i != m_strata.Count - 1) { outWs.Stratum = m_strata[i + 1]; } if (m_traceStrataSynthesis) { // create the stratum synthesis output trace record for the output analysis outWs.CurrentTrace.AddChild(new StratumSynthesisTrace(m_strata[i], false, outWs.Clone())); } outSynthesis.Add(outWs); } } inSynthesis.Clear(); inSynthesis.AddMany(outSynthesis); } foreach (WordSynthesis ws in outSynthesis) { if (ws.IsValid) { allValidSyntheses.Add(ws); } } } Set <WordSynthesis> results = new Set <WordSynthesis>(); // sort the resulting syntheses according to the order of precedence of each allomorph in // their respective morphemes List <WordSynthesis> sortedSyntheses = new List <WordSynthesis>(allValidSyntheses); sortedSyntheses.Sort(); WordSynthesis prevValidSynthesis = null; foreach (WordSynthesis cur in sortedSyntheses) { // enforce the disjunctive property of allomorphs by ensuring that this word synthesis // has the highest order of precedence for its allomorphs while also allowing for free // fluctuation, also check that the phonetic shape matches the original input word if ((prevValidSynthesis == null || AreAllomorphsNondisjunctive(cur, prevValidSynthesis)) && SurfaceStratum.CharacterDefinitionTable.IsMatch(word, cur.Shape)) { if (m_traceSuccess) { // create the report a success output trace record for the output analysis cur.CurrentTrace.AddChild(new ReportSuccessTrace(cur)); } // do not add to the result if it has the same root, shape, and morphemes as another result bool duplicate = false; foreach (WordSynthesis ws in results) { if (cur.Duplicates(ws)) { duplicate = true; break; } } if (!duplicate) { results.Add(cur); } } prevValidSynthesis = cur; } return(results); }
/// <summary> /// Determines whether the specified word matches the specified phonetic shape. /// </summary> /// <param name="word">The word.</param> /// <param name="shape">The phonetic shape.</param> /// <returns> /// <c>true</c> if the word matches the shape, otherwise <c>false</c>. /// </returns> public virtual bool IsMatch(string word, PhoneticShape shape) { string pattern = ToRegexString(shape, ModeType.SYNTHESIS, false); return(Regex.IsMatch(word, pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)); }