/// <summary> /// Parses the specified text representing a misspelling transform /// operation. /// </summary> /// <param name="text">The text.</param> /// <returns>operation, or null if invalid text</returns> public static MspOperation Parse(string text) { if (string.IsNullOrWhiteSpace(text)) { return(null); } Match m = _opRegex.Match(text); if (!m.Success) { return(null); } MspOperation operation = new MspOperation { RangeA = new TextRange( ParseRangeNumber(m.Groups["ras"].Value), ParseRangeNumber(m.Groups["ral"].Value)), ValueA = m.Groups["va"].Length > 0 ? m.Groups["va"].Value : null, RangeB = new TextRange( ParseRangeNumber(m.Groups["rbs"].Value), ParseRangeNumber(m.Groups["rbl"].Value)), ValueB = m.Groups["vb"].Length > 0 ? m.Groups["vb"].Value : null, Tag = m.Groups["tag"].Length > 0 ? m.Groups["tag"].Value : null, Note = m.Groups["note"].Length > 0 ? m.Groups["note"].Value : null }; DetermineOperator(m.Groups["op"].Value, operation); // range B is allowed only for move/swap if (operation._operator != MspOperator.Move && operation._operator != MspOperator.Swap) { operation.RangeB = TextRange.Empty; } // value B is allowed only for insert/replace/swap if (operation._operator != MspOperator.Insert && operation._operator != MspOperator.Replace && operation._operator != MspOperator.Swap) { operation.ValueB = null; } return(operation); }
/// <summary> /// Get all the pins exposed by the implementor. /// </summary> /// <remarks>If operations have tags, the operations with tags are /// grouped by them, and a pin is returned for each group, with its name /// equal to <c>fr.msp</c> + the grouped operations tag, and its value /// equal to the count of such operations. These pins are sorted /// by their name.</remarks> /// <returns>pins</returns> public IEnumerable <DataPin> GetDataPins() { if (Operations?.Count == 0) { return(Enumerable.Empty <DataPin>()); } var groups = from s in Operations let o = MspOperation.Parse(s) where o?.Tag != null group o by o.Tag into g select g; return(from g in groups orderby g.Key select new DataPin { Name = PartBase.FR_PREFIX + $"msp.{g.Key}", Value = g.Count().ToString(CultureInfo.InvariantCulture) }); }
private static void DetermineOperator(string text, MspOperation operation) { switch (text) { case "=": if (operation.ValueB == null) { operation.Operator = MspOperator.Delete; break; } operation.Operator = operation.RangeA.Length == 0? MspOperator.Insert : MspOperator.Replace; break; case ">": operation.Operator = MspOperator.Move; break; case "~": operation.Operator = MspOperator.Swap; break; } }
/// <summary> /// Get all the pins exposed by the implementor. /// </summary> /// <param name="item">The optional item. The item with its parts /// can optionally be passed to this method for those parts requiring /// to access further data.</param> /// <remarks>If operations have tags, the operations with tags are /// grouped by them, and a pin is returned for each group, with its name /// equal to <c>fr.msp</c> + the grouped operations tag, and its value /// equal to the count of such operations. These pins are sorted /// by their name. /// <para>Also, if <paramref name="item"/> is received and it has /// a base text part and an orthography layer part, two additional pins /// are returned: <c>fr.orthography-txt</c> with the original orthography /// got from the base text, and <c>fr.orthography.std</c> with the /// <see cref="Standard"/> orthography from this fragment.</para> /// </remarks> /// <returns>pins</returns> public IEnumerable <DataPin> GetDataPins(IItem item = null) { List <DataPin> pins = new List <DataPin>(); if (Operations?.Count > 0) { var groups = from s in Operations let o = MspOperation.Parse(s) where o?.Tag != null group o by o.Tag into g select g; pins.AddRange( from g in groups orderby g.Key select new DataPin { Name = PartBase.FR_PREFIX + $"msp.{g.Key}", Value = g.Count().ToString(CultureInfo.InvariantCulture) }); } if (item != null) { // get the base text part IPart textPart = item.Parts .Find(p => p.RoleId == PartBase.BASE_TEXT_ROLE_ID); if (textPart == null) { return(pins); } // get the orthography layer TagAttribute attr = GetType().GetTypeInfo() .GetCustomAttribute <TagAttribute>(); Regex roleIdRegex = new Regex("^" + attr.Tag + "(?::.+)?$"); IHasFragments <OrthographyLayerFragment> layerPart = item.Parts.Find(p => p.RoleId != null && roleIdRegex.IsMatch(p.RoleId)) as IHasFragments <OrthographyLayerFragment>; if (layerPart == null) { return(pins); } string baseText = layerPart.GetTextAt(textPart, Location); if (baseText != null) { pins.Add(new DataPin { Name = PartBase.FR_PREFIX + "orthography-txt", Value = baseText }); pins.Add(new DataPin { Name = PartBase.FR_PREFIX + "orthography-std", Value = Standard }); } } return(pins); }
private void DetectMoves(List <Tuple <Diff, MspOperation> > mspDiffs) { // first look for INS..DEL for (int i = 0; i < mspDiffs.Count; i++) { // for each INS: if (mspDiffs[i].Item2?.Operator == MspOperator.Insert) { MspOperation ins = mspDiffs[i].Item2; // find a DEL with the same value var nextDel = mspDiffs .Skip(i + 1) .FirstOrDefault(t => t.Item2?.Operator == MspOperator.Delete && t.Item2.ValueA == ins.ValueB); // if found, assume a MOV from DEL to INS if (nextDel != null) { int nextDelIndex = mspDiffs.IndexOf(nextDel); MspOperation del = mspDiffs[nextDelIndex].Item2; mspDiffs[nextDelIndex] = Tuple.Create(mspDiffs[nextDelIndex].Item1, new MspOperation { Operator = MspOperator.Move, RangeA = del.RangeA, RangeB = ins.RangeA, ValueA = del.ValueA }); mspDiffs.RemoveAt(i--); } } } // then look for DEL..INS for (int i = 0; i < mspDiffs.Count; i++) { // for each DEL: if (mspDiffs[i].Item2?.Operator == MspOperator.Delete) { // find an INS with the same value MspOperation del = mspDiffs[i].Item2; var nextIns = mspDiffs .Skip(i + 1) .FirstOrDefault(t => t.Item2?.Operator == MspOperator.Insert && t.Item2.ValueB == del.ValueA); // if found, assume a MOV from DEL to INS if (nextIns != null) { MspOperation ins = nextIns.Item2; int nextInsIndex = mspDiffs.IndexOf(nextIns); mspDiffs[i] = Tuple.Create(mspDiffs[i].Item1, new MspOperation { Operator = MspOperator.Move, RangeA = del.RangeA, RangeB = ins.RangeA, ValueA = del.ValueA }); mspDiffs.RemoveAt(nextInsIndex); } } } }