// Operations /// <summary> /// Parses a string entity for nuggets, forwarding the nugget to a caller-provided /// delegate, with support for replacement of nugget strings in the entity. /// </summary> /// <param name="entity"> /// String containing nuggets to be parsed. E.g. source code file, HTTP response entity. /// </param> /// <param name="ProcessNugget"> /// Delegate callback to be called for each nugget encountered in entity: /// delegate(string nuggetString, int pos, Nugget nugget1, string entity1). /// Returns a string with which to replace the nugget string in the source entity. /// If no change, then may return null. /// </param> /// <returns> /// Entity string reflecting any nugget strings replacements. /// </returns> public string ParseString( string entity, Func <string, int, Nugget, string, string> ProcessNugget) { if (entity == null) { return(""); } // Note that this method has two-levels of delegates: // Outer delegate is the delegate which is called by regex as it matches each nugget // Inner delegate is the client callback delegate (ProcessNugget) which we call from the outer delegate. // // Lookup any/all nuggets in the entity and call the client delegate (ProcessNugget) for each. return(m_regexNuggetBreakdown.Replace(entity, delegate(Match match) { Nugget nugget = NuggetFromRegexMatch(match); // string modifiedNuggetString = ProcessNugget( match.Groups[0].Value, // entire nugget string match.Groups[0].Index, // zero-based pos of the first char of entire nugget string nugget, // broken-down nugget entity); // source entity string // Returns either modified nugget string, or original nugget string (i.e. for no replacement). return modifiedNuggetString ?? match.Groups[0].Value; })); }
public override bool Equals(object obj) { if (obj == null) { return(false); } if (this.GetType() != obj.GetType()) { return(false); } Nugget other = (Nugget)obj; // Compare non-array members. if (MsgId != other.MsgId || // NB: the operator==() on string objects handles null value on either side just fine. Comment != other.Comment) { return(false); } // Compare arrays. if ((FormatItems == null) != (other.FormatItems == null) || (FormatItems != null && !FormatItems.SequenceEqual(other.FormatItems))) { return(false); } return(true); }
private void ParseAndComp(string nuggetString, Nugget rhs, bool equal = true) { // Arrange. NuggetTokens nuggetTokens = new NuggetTokens("[[[", "]]]", "|||", "///"); NuggetParser nuggetParser = new NuggetParser(nuggetTokens, NuggetParser.Context.SourceProcessing); // Act. Nugget nugget = nuggetParser.BreakdownNugget(nuggetString); // Assert. if (equal) { Assert.AreEqual(nugget, rhs); } else { Assert.AreNotEqual(nugget, rhs); } }
private void CompareNugget(Nugget n1, Nugget n2, bool equal) { // Test equality. if (equal) { Assert.AreEqual(n1, n2); } else { Assert.AreNotEqual(n1, n2); } // Test hash code. int h1 = n1.GetHashCode(); int h2 = n2.GetHashCode(); // · If two objects are equal then they must have the same hash code. if (n1.Equals(n2)) { Assert.AreEqual(h1, h2); } // · If two objects have different hash codes then they must be unequal. if (h1 != h2) { Assert.AreNotEqual(n1, n2); } }
/// <summary> /// Returns a nugget instance loaded from a regex match, or null if error. /// </summary> private Nugget NuggetFromRegexMatch(Match match) { if (!match.Success || match.Groups.Count != 4) { return(null); } Nugget n = new Nugget(); // Extract msgid from 2nd capture group. n.MsgId = match.Groups[1].Value; // Extract format items from 3rd capture group. var formatItems = match.Groups[2].Captures; if (formatItems.Count != 0) { n.FormatItems = new string[formatItems.Count]; int i = 0; foreach (Capture capture in formatItems) { if (m_context == Context.SourceProcessing && !capture.Value.IsSet()) { return(null); } // bad format n.FormatItems[i++] = capture.Value; } } // Extract comment from 4th capture group. if (match.Groups[3].Value.IsSet()) { n.Comment = match.Groups[3].Value; } // Success. return(n); }
private void AddNewTemplateItem( string filePath, int lineNumber, Nugget nugget, ConcurrentDictionary<string, TemplateItem> templateItems) { string reference = filePath + ":" + lineNumber.ToString(); string msgid = nugget.MsgId.Replace("\r\n", "\n").Replace("\r", "\\n"); // NB: In memory msgids are normalized so that LFs are converted to "\n" char sequence. string key = TemplateItem.KeyFromMsgidAndComment(msgid, nugget.Comment, _settings.MessageContextEnabledFromComment); List<string> tmpList; // templateItems.AddOrUpdate( key, // Add routine. k => { TemplateItem item = new TemplateItem(); item.MsgKey = key; item.MsgId = msgid; tmpList = new List<string>(); tmpList.Add(reference); item.References = tmpList; if (nugget.Comment.IsSet()) { tmpList = new List<string>(); tmpList.Add(nugget.Comment); item.Comments = tmpList; } return item; }, // Update routine. (k, v) => { tmpList = v.References.ToList(); tmpList.Add(reference); v.References = tmpList; if (nugget.Comment.IsSet()) { tmpList = v.Comments != null ? v.Comments.ToList() : new List<string>(); tmpList.Add(nugget.Comment); v.Comments = tmpList; } return v; }); }
/// <summary> /// Process nugget. /// </summary> /// <param name="position">Position right after begin token.</param> /// <returns>Parse result.</returns> private ParseAndProccessResult ParseAndProcessNugget(int position, bool isNested) { // Position of the comment block starting from token int?commentStartPosition = null; int?parameterStartPosition = null; bool wasNestedNugget = false; var nugget = new Nugget(); var formatItems = new List <string>(); int nextPosition = position + m_owner.m_nuggetTokens.BeginToken.Length; for (;;) { var match = m_owner.m_tokensRegex.Match(m_entity, nextPosition); if (!match.Success) { return(new ParseAndProccessResult { Replacement = m_entity.Substring(position), NextPosition = m_entity.Length }); } // Ignoring unexpected start of nugget. if (match.Value == m_owner.m_nuggetTokens.BeginToken) { nextPosition = match.Index + match.Length; continue; } // Processing unexected parameter end - ))) if (match.Value == m_owner.m_parameterEndBeforeDelimiterToken || match.Value == m_owner.m_parameterEndBeforeEndToken) { if (isNested) { return(new ParseAndProccessResult { Replacement = m_entity.Substring( position, match.Index - position), NextPosition = match.Index, ContainNuggets = true }); } nextPosition = match.Index + m_owner.m_nuggetTokens.ParameterEndToken.Length; continue; } // Skipping all tokens except NuggetEnd after comment was found. if (commentStartPosition != null && match.Value != m_owner.m_nuggetTokens.EndToken) { nextPosition = match.Index + match.Length; continue; } // Saving msgid and comment once parameter or end of nugget found. if (nugget.MsgId == null) { nugget.MsgId = m_entity.Substring( position + m_owner.m_nuggetTokens.BeginToken.Length, match.Index - position - m_owner.m_nuggetTokens.BeginToken.Length); } // Saving parameter start position if (parameterStartPosition != null) { var formatItemString = m_entity.Substring( parameterStartPosition.Value + m_owner.m_nuggetTokens.DelimiterToken.Length, match.Index - parameterStartPosition.Value - m_owner.m_nuggetTokens.DelimiterToken.Length); formatItems.Add(formatItemString); } // Processing parameter with nesting - |||((( if (match.Value == m_owner.m_delimiterWithParameterBeginToken) { wasNestedNugget = true; var result = ParseAndProcessNuggetZone(match.Index + match.Length, true); nextPosition = result.NextPosition; formatItems.Add(result.Replacement); parameterStartPosition = null; continue; } // Processing simple parameter if (match.Value == m_owner.m_nuggetTokens.DelimiterToken) { parameterStartPosition = match.Index; nextPosition = match.Index + match.Length; continue; } // Saving comment start position if (match.Value == m_owner.m_nuggetTokens.CommentToken) { if (commentStartPosition == null) { commentStartPosition = match.Index; } nextPosition = match.Index + match.Length; continue; } if (match.Value == m_owner.m_nuggetTokens.EndToken) { if (commentStartPosition != null) { var commentTextStartPos = commentStartPosition.Value + m_owner.m_nuggetTokens.CommentToken.Length; nugget.Comment = m_entity.Substring(commentTextStartPos, match.Index - commentTextStartPos); } if (nugget.MsgId != string.Empty) { var result = new ParseAndProccessResult { ContainNuggets = true, NextPosition = match.Index + match.Length }; if (formatItems.Any() && m_owner.m_context == NuggetParser.Context.ResponseProcessing) { nugget.FormatItems = formatItems.ToArray(); } if (wasNestedNugget) { // Virtualization required var virtualEntity = new StringBuilder(); virtualEntity.Append(m_owner.m_nuggetTokens.BeginToken); virtualEntity.Append(nugget.MsgId); if (nugget.Comment != null) { virtualEntity.Append(m_owner.m_nuggetTokens.CommentToken); virtualEntity.Append(nugget.Comment); } foreach (var formatItem in formatItems) { virtualEntity.Append(m_owner.m_nuggetTokens.DelimiterToken); virtualEntity.Append(formatItem); } virtualEntity.Append(m_owner.m_nuggetTokens.EndToken); var virtualEntityString = virtualEntity.ToString(); // Processing nugget var originalMsgId = nugget.MsgId; nugget.MsgId = PreProccessMsgId(nugget.MsgId); var replaceString = m_processNugget(virtualEntityString, 0, nugget, virtualEntityString); result.Replacement = replaceString ?? originalMsgId; } else { // Processing nugget var originalMsgId = nugget.MsgId; nugget.MsgId = PreProccessMsgId(nugget.MsgId); var replaceString = m_processNugget( m_entity.Substring( position, match.Index + match.Length - position), // entire nugget string position, // zero-based pos of the first char of entire nugget string nugget, // broken-down nugget m_entity); // source entity string result.Replacement = replaceString ?? originalMsgId; } return(result); } return(new ParseAndProccessResult { Replacement = string.Empty, ContainNuggets = true, NextPosition = match.Index + match.Length }); } } }
private ParseAndProccessResult ParseAndProcessNuggetZone(int position, bool isNested) { bool containsNuggets = false; StringBuilder processedZone = new StringBuilder(); int nextPosition = position; for (;;) { var match = m_owner.m_tokensRegex.Match(m_entity, nextPosition); if (!match.Success) { processedZone.Append( m_entity.Substring(nextPosition)); return(new ParseAndProccessResult { Replacement = processedZone.ToString() }); } if (match.Value == m_owner.m_nuggetTokens.BeginToken) { processedZone.Append(m_entity.Substring(nextPosition, match.Index - nextPosition)); var processedNugget = ParseAndProcessNugget(match.Index, isNested); processedZone.Append(processedNugget.Replacement); nextPosition = processedNugget.NextPosition; containsNuggets = true; continue; } if (isNested) { if (IsParameterEnd(match.Value)) { if (!containsNuggets) { // This is original behavior of ((())). var stringToProccess = m_entity.Substring(nextPosition, match.Index - nextPosition); var nugget = new Nugget { MsgId = stringToProccess }; string modifiedNuggetString = null; if (m_owner.m_context == NuggetParser.Context.SourceProcessing) { string fakeNuggetString = string.Format( "{0}{1}{2}", m_owner.m_nuggetTokens.BeginToken, stringToProccess, m_owner.m_nuggetTokens.EndToken); nugget.MsgId = PreProccessMsgId(nugget.MsgId); modifiedNuggetString = m_processNugget( fakeNuggetString, // entire nugget string m_owner.m_nuggetTokens.BeginToken.Length, // zero-based pos of the first char of entire nugget string nugget, // broken-down nugget fakeNuggetString); // source entity string // Returns either modified nugget string, or original nugget string (i.e. for no replacement). } return(new ParseAndProccessResult { Replacement = modifiedNuggetString ?? stringToProccess, NextPosition = match.Index + m_owner.m_nuggetTokens.ParameterEndToken.Length, ContainNuggets = containsNuggets }); } processedZone.Append(m_entity.Substring(nextPosition, match.Index - nextPosition)); return(new ParseAndProccessResult { Replacement = processedZone.ToString(), NextPosition = match.Index + m_owner.m_nuggetTokens.ParameterEndToken.Length, ContainNuggets = containsNuggets }); } } processedZone.Append(m_entity.Substring(nextPosition, match.Index + match.Length - nextPosition)); nextPosition = match.Index + match.Length; } }
/// <summary> /// Returns a nugget instance loaded from a regex match, or null if error. /// </summary> private Nugget NuggetFromRegexMatch(Match match) { if (!match.Success || match.Groups.Count != 4) { return null; } Nugget n = new Nugget(); // Extract msgid from 2nd capture group. n.MsgId = match.Groups[1].Value; // Extract format items from 3rd capture group. var formatItems = match.Groups[2].Captures; if (formatItems.Count != 0) { n.FormatItems = new string[formatItems.Count]; int i = 0; foreach (Capture capture in formatItems) { if (m_context == Context.SourceProcessing && !capture.Value.IsSet()) { return null; } // bad format n.FormatItems[i++] = capture.Value; } } // Extract comment from 4th capture group. if (match.Groups[3].Value.IsSet()) { n.Comment = match.Groups[3].Value; } // Success. return n; }
public void Nugget_EqualsAndHashCode() { Nugget nugget01 = new Nugget { MsgId = "msgid" }; Nugget nugget02 = new Nugget { MsgId = "msgid", FormatItems = new string[] { "fi1", "fi2" } }; Nugget nugget03 = new Nugget { MsgId = "msgid", Comment = "comment" }; Nugget nugget04 = new Nugget { MsgId = "msgid", FormatItems = new string[] { "fi1", "fi2" }, Comment = "comment" }; Nugget nugget05 = new Nugget { MsgId = "msgid", FormatItems = new string[] { "fi1" } }; Nugget nugget06 = new Nugget { MsgId = "msgid", FormatItems = new string[] {}, Comment = "comment" }; Nugget nugget11 = new Nugget { MsgId = "msgid" }; Nugget nugget12 = new Nugget { MsgId = "msgid", FormatItems = new string[] { "fi1", "fi2" } }; Nugget nugget13 = new Nugget { MsgId = "msgid", Comment = "comment" }; Nugget nugget14 = new Nugget { MsgId = "msgid", FormatItems = new string[] { "fi1", "fi2" }, Comment = "comment" }; Nugget nugget15 = new Nugget { MsgId = "msgid", FormatItems = new string[] { "fi1" } }; Nugget nugget16 = new Nugget { MsgId = "msgid", FormatItems = new string[] {}, Comment = "comment" }; CompareNugget(nugget01, nugget01, true); CompareNugget(nugget02, nugget02, true); CompareNugget(nugget03, nugget03, true); CompareNugget(nugget04, nugget04, true); CompareNugget(nugget05, nugget05, true); CompareNugget(nugget06, nugget06, true); CompareNugget(nugget01, nugget11, true); CompareNugget(nugget02, nugget12, true); CompareNugget(nugget03, nugget13, true); CompareNugget(nugget04, nugget14, true); CompareNugget(nugget05, nugget15, true); CompareNugget(nugget06, nugget16, true); CompareNugget(nugget01, nugget11, true); CompareNugget(nugget02, nugget11, false); CompareNugget(nugget03, nugget11, false); CompareNugget(nugget04, nugget11, false); CompareNugget(nugget05, nugget11, false); CompareNugget(nugget06, nugget11, false); CompareNugget(nugget01, nugget12, false); CompareNugget(nugget02, nugget12, true); CompareNugget(nugget03, nugget12, false); CompareNugget(nugget04, nugget12, false); CompareNugget(nugget05, nugget12, false); CompareNugget(nugget06, nugget12, false); CompareNugget(nugget01, nugget13, false); CompareNugget(nugget02, nugget13, false); CompareNugget(nugget03, nugget13, true); CompareNugget(nugget04, nugget13, false); CompareNugget(nugget05, nugget13, false); CompareNugget(nugget06, nugget13, false); CompareNugget(nugget01, nugget14, false); CompareNugget(nugget02, nugget14, false); CompareNugget(nugget03, nugget14, false); CompareNugget(nugget04, nugget14, true); CompareNugget(nugget05, nugget14, false); CompareNugget(nugget06, nugget14, false); CompareNugget(nugget01, nugget15, false); CompareNugget(nugget02, nugget15, false); CompareNugget(nugget03, nugget15, false); CompareNugget(nugget04, nugget15, false); CompareNugget(nugget05, nugget15, true); CompareNugget(nugget06, nugget15, false); CompareNugget(nugget01, nugget16, false); CompareNugget(nugget02, nugget16, false); CompareNugget(nugget03, nugget16, false); CompareNugget(nugget04, nugget16, false); CompareNugget(nugget05, nugget16, false); CompareNugget(nugget06, nugget16, true); }
private void AddNewTemplateItem( string fileName, ReferenceContext referenceContext, Nugget nugget, ConcurrentDictionary<string, TemplateItem> templateItems) { string msgid = nugget.MsgId.Replace("\r\n", "\n").Replace("\r", "\\n"); // NB: In memory msgids are normalized so that LFs are converted to "\n" char sequence. string key = TemplateItem.KeyFromMsgidAndComment(msgid, nugget.Comment, _settings.MessageContextEnabledFromComment); List<string> tmpList; // templateItems.AddOrUpdate( key, // Add routine. k => { TemplateItem item = new TemplateItem(); item.MsgKey = key; item.MsgId = msgid; item.FileName = fileName; item.References = new List<ReferenceContext> {referenceContext}; if (nugget.Comment.IsSet()) { tmpList = new List<string>(); tmpList.Add(nugget.Comment); item.Comments = tmpList; } return item; }, // Update routine. (k, v) => { if (!_settings.DisableReferences) { var newReferences = new List<ReferenceContext>(v.References.ToList()); newReferences.Add(referenceContext); v.References = newReferences; } if (nugget.Comment.IsSet()) { tmpList = v.Comments != null ? v.Comments.ToList() : new List<string>(); if (!_settings.DisableReferences || !tmpList.Contains(nugget.Comment)) tmpList.Add(nugget.Comment); v.Comments = tmpList; } return v; }); }