Reputation: 34539
I'm trying to build a regex statement, but am obviously mis-understanding something. I've got a C# StackTrace
and want to essentially crop the end of the string until I see the first instance of our namespace. Here is a section of the data to illustrate - with a manually positioned new line to illustrate where I'm trying to match to.
at MooD.LandscapeExplorer.Controllers.LandscapeController.GetContextInstanceCount(BusinessContext context) in C:\Source\MooDEdge\Code\MooD16\MooD.LandscapeExplorer\Controllers\LandscapeController.cs:line 143
at System.Linq.Enumerable.<SelectManyIterator>d__1`2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at MooD.LandscapeExplorer.Controllers.LandscapeController.ProcessContext(String[] types, String[] instances, QueryFilter[] filters) in C:\Source\MooDEdge\Code\MooD16\MooD.LandscapeExplorer\Controllers\LandscapeController.cs:line 125
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation.InvokeSynchronousActionMethod()
So I want to keep the first half, and remove the second half from the string. I've used a negative lookahead (I grabbed from another question, I don't really understand how it works), to match on anything other than MooD
. Then I've stuck on an end of string $
.
(at (?!MooD).*)$
At this point I thought all I needed to do was to add a *
to match lots of the previous group, turning the regex into:
(at (?!MooD).*)*$
However this doesn't work as I expected when testing on https://regex101.com/. It still just matches the final instance. I've also tried adding in a new line detection, but that still only matches the final line:
(at (?!MooD).*\n?)*$
Could anyone explain how I can match the rest, and why this solution doesn't work?
Upvotes: 1
Views: 59
Reputation: 11273
I know you are trying to do this with regex, but here is a non-regex option:
public static string GetMooDStackTrace(string stackTrace)
{
var lines = stackTrace.Split('\n');
int lastLineWithMood = -1;
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains("MooD"))
lastLineWithMood = i;
}
return string.Join("\n", lines, 0, lastLineWithMood + 1);
}
From your input, produces:
at MooD.LandscapeExplorer.Controllers.LandscapeController.GetContextInstanceCount(BusinessContext context) in C:\Source\MooDEdge\Code\MooD16\MooD.LandscapeExplorer\Controllers\LandscapeController.cs:line 143 at System.Linq.Enumerable.d__1`2.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at MooD.LandscapeExplorer.Controllers.LandscapeController.ProcessContext(String[] types, String[] instances, QueryFilter[] filters) in C:\Source\MooDEdge\Code\MooD16\MooD.LandscapeExplorer\Controllers\LandscapeController.cs:line 125
Upvotes: 0
Reputation: 785971
To match bottom part you can use this negative lookahead based regex:
at (?:(?!MooD)[\s\S])*$
(?:(?!MooD)[\s\S])*
will match 0 or more of any character while asserting that no character has MooD
at next position.
[\s\S]
will match any character including newline.
PS: It is safer to use word boundary:
at (?:(?!\bMooD\b)[\s\S])*$
Upvotes: 2