Skip to content

Commit c85771f

Browse files
authored
Merge pull request #123 from nblumhardt/replace
`Replace()` function
2 parents 36dfc70 + 0176b2d commit c85771f

File tree

6 files changed

+87
-51
lines changed

6 files changed

+87
-51
lines changed

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,22 +189,23 @@ calling a function will be undefined if:
189189

190190
| Function | Description |
191191
|:--------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
192-
| `Coalesce(p0, p1, [..pN])` | Returns the first defined, non-null argument. |
192+
| `Coalesce(a0, a1, [..aN])` | Returns the first defined, non-null argument. |
193193
| `Concat(s0, s1, [..sN])` | Concatenate two or more strings. |
194-
| `Contains(s, t)` | Tests whether the string `s` contains the substring `t`. |
194+
| `Contains(s, p)` | Tests whether the string `s` contains the substring `p`. |
195195
| `ElementAt(x, i)` | Retrieves a property of `x` by name `i`, or array element of `x` by numeric index `i`. |
196-
| `EndsWith(s, t)` | Tests whether the string `s` ends with substring `t`. |
197-
| `IndexOf(s, t)` | Returns the first index of substring `t` in string `s`, or -1 if the substring does not appear. |
196+
| `EndsWith(s, p)` | Tests whether the string `s` ends with substring `p`. |
197+
| `IndexOf(s, p)` | Returns the first index of substring `p` in string `s`, or -1 if the substring does not appear. |
198198
| `IndexOfMatch(s, p)` | Returns the index of the first match of regular expression `p` in string `s`, or -1 if the regular expression does not match. |
199199
| `Inspect(o, [deep])` | Read properties from an object captured as the scalar value `o`. |
200200
| `IsMatch(s, p)` | Tests whether the regular expression `p` matches within the string `s`. |
201201
| `IsDefined(x)` | Returns `true` if the expression `x` has a value, including `null`, or `false` if `x` is undefined. |
202-
| `LastIndexOf(s, t)` | Returns the last index of substring `t` in string `s`, or -1 if the substring does not appear. |
202+
| `LastIndexOf(s, p)` | Returns the last index of substring `p` in string `s`, or -1 if the substring does not appear. |
203203
| `Length(x)` | Returns the length of a string or array. |
204204
| `Now()` | Returns `DateTimeOffset.Now`. |
205+
| `Replace(s, p, r)` | Replace occurrences of substring `p` in string `s` with replacement `r`. |
205206
| `Rest([deep])` | In an `ExpressionTemplate`, returns an object containing the first-class event properties not otherwise referenced in the template. If `deep` is `true`, also excludes properties referenced in the event's message template. |
206207
| `Round(n, m)` | Round the number `n` to `m` decimal places. |
207-
| `StartsWith(s, t)` | Tests whether the string `s` starts with substring `t`. |
208+
| `StartsWith(s, p)` | Tests whether the string `s` starts with substring `p`. |
208209
| `Substring(s, start, [length])` | Return the substring of string `s` from `start` to the end of the string, or of `length` characters, if this argument is supplied. |
209210
| `TagOf(o)` | Returns the `TypeTag` field of a captured object (i.e. where `TypeOf(x)` is `'object'`). |
210211
| `ToString(x, [format])` | Convert `x` to a string, applying the format string `format` if `x` is `IFormattable`. |

src/Serilog.Expressions/Expressions/Helpers.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using System.Text.RegularExpressions;
16+
1517
#if NO_CI_STRING_CONTAINS
1618

1719
namespace Serilog.Expressions
@@ -29,13 +31,27 @@ static class Helpers
2931
/// https://github.com/dotnet/runtime/issues/22198
3032
/// https://stackoverflow.com/questions/444798/case-insensitive-containsstring/444818#444818
3133
/// </summary>
32-
/// <param name="source">input string</param>
34+
/// <param name="this">input string</param>
3335
/// <param name="value">The string to seek.</param>
3436
/// <param name="comparisonType">Specifies the rule to use in the comparison.</param>
3537
/// <returns></returns>
36-
public static bool Contains(this string source, string value, StringComparison comparisonType)
38+
public static bool Contains(this string @this, string value, StringComparison comparisonType)
3739
{
38-
return source.IndexOf(value, comparisonType) >= 0;
40+
return @this.IndexOf(value, comparisonType) >= 0;
41+
}
42+
43+
public static string Replace(this string @this, string oldValue, string newValue, StringComparison comparisonType)
44+
{
45+
if ("a".Equals("A", comparisonType))
46+
{
47+
return Regex.Replace(
48+
@this,
49+
Regex.Escape(oldValue),
50+
newValue.Replace("$", "$$"),
51+
RegexOptions.IgnoreCase);
52+
}
53+
54+
return @this.Replace(oldValue, newValue);
3955
}
4056
}
4157
}

src/Serilog.Expressions/Expressions/Operators.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static class Operators
3939
public const string OpLastIndexOf = "LastIndexOf";
4040
public const string OpLength = "Length";
4141
public const string OpNow = "Now";
42+
public const string OpReplace = "Replace";
4243
public const string OpRound = "Round";
4344
public const string OpStartsWith = "StartsWith";
4445
public const string OpSubstring = "Substring";

src/Serilog.Expressions/Expressions/Runtime/RuntimeOperators.cs

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,16 @@ static bool UnboxedEqualHelper(StringComparison sc, LogEventPropertyValue? left,
230230
return ScalarBoolean(!UnboxedEqualHelper(sc, left, right));
231231
}
232232

233-
public static LogEventPropertyValue? _Internal_Negate(LogEventPropertyValue? operand)
233+
public static LogEventPropertyValue? _Internal_Negate(LogEventPropertyValue? value)
234234
{
235-
if (Coerce.Numeric(operand, out var numeric))
235+
if (Coerce.Numeric(value, out var numeric))
236236
return new ScalarValue(-numeric);
237237
return null;
238238
}
239239

240-
public static LogEventPropertyValue? Round(LogEventPropertyValue? number, LogEventPropertyValue? places)
240+
public static LogEventPropertyValue? Round(LogEventPropertyValue? value, LogEventPropertyValue? places)
241241
{
242-
if (!Coerce.Numeric(number, out var v) ||
242+
if (!Coerce.Numeric(value, out var v) ||
243243
!Coerce.Numeric(places, out var p) ||
244244
p is < 0 or > 32) // Check my memory, here :D
245245
{
@@ -249,45 +249,45 @@ static bool UnboxedEqualHelper(StringComparison sc, LogEventPropertyValue? left,
249249
return new ScalarValue(Math.Round(v, (int)p));
250250
}
251251

252-
public static LogEventPropertyValue? _Internal_Not(LogEventPropertyValue? operand)
252+
public static LogEventPropertyValue? _Internal_Not(LogEventPropertyValue? value)
253253
{
254-
if (operand is null)
254+
if (value is null)
255255
return ConstantTrue;
256256

257-
return Coerce.Boolean(operand, out var b) ?
257+
return Coerce.Boolean(value, out var b) ?
258258
ScalarBoolean(!b) :
259259
null;
260260
}
261261

262-
public static LogEventPropertyValue? _Internal_StrictNot(LogEventPropertyValue? operand)
262+
public static LogEventPropertyValue? _Internal_StrictNot(LogEventPropertyValue? value)
263263
{
264-
return Coerce.Boolean(operand, out var b) ?
264+
return Coerce.Boolean(value, out var b) ?
265265
ScalarBoolean(!b) :
266266
null;
267267
}
268268

269-
public static LogEventPropertyValue? Contains(StringComparison sc, LogEventPropertyValue? @string, LogEventPropertyValue? substring)
269+
public static LogEventPropertyValue? Contains(StringComparison sc, LogEventPropertyValue? haystack, LogEventPropertyValue? needle)
270270
{
271-
if (!Coerce.String(@string, out var ctx) ||
272-
!Coerce.String(substring, out var ptx))
271+
if (!Coerce.String(haystack, out var ctx) ||
272+
!Coerce.String(needle, out var ptx))
273273
return null;
274274

275275
return ScalarBoolean(ctx.Contains(ptx, sc));
276276
}
277277

278-
public static LogEventPropertyValue? IndexOf(StringComparison sc, LogEventPropertyValue? @string, LogEventPropertyValue? substring)
278+
public static LogEventPropertyValue? IndexOf(StringComparison sc, LogEventPropertyValue? haystack, LogEventPropertyValue? needle)
279279
{
280-
if (!Coerce.String(@string, out var ctx) ||
281-
!Coerce.String(substring, out var ptx))
280+
if (!Coerce.String(haystack, out var ctx) ||
281+
!Coerce.String(needle, out var ptx))
282282
return null;
283283

284284
return new ScalarValue(ctx.IndexOf(ptx, sc));
285285
}
286286

287-
public static LogEventPropertyValue? LastIndexOf(StringComparison sc, LogEventPropertyValue? @string, LogEventPropertyValue? substring)
287+
public static LogEventPropertyValue? LastIndexOf(StringComparison sc, LogEventPropertyValue? haystack, LogEventPropertyValue? needle)
288288
{
289-
if (!Coerce.String(@string, out var ctx) ||
290-
!Coerce.String(substring, out var ptx))
289+
if (!Coerce.String(haystack, out var ctx) ||
290+
!Coerce.String(needle, out var ptx))
291291
return null;
292292

293293
return new ScalarValue(ctx.LastIndexOf(ptx, sc));
@@ -304,19 +304,19 @@ static bool UnboxedEqualHelper(StringComparison sc, LogEventPropertyValue? left,
304304
return null;
305305
}
306306

307-
public static LogEventPropertyValue? StartsWith(StringComparison sc, LogEventPropertyValue? value, LogEventPropertyValue? substring)
307+
public static LogEventPropertyValue? StartsWith(StringComparison sc, LogEventPropertyValue? haystack, LogEventPropertyValue? needle)
308308
{
309-
if (!Coerce.String(value, out var ctx) ||
310-
!Coerce.String(substring, out var ptx))
309+
if (!Coerce.String(haystack, out var ctx) ||
310+
!Coerce.String(needle, out var ptx))
311311
return null;
312312

313313
return ScalarBoolean(ctx.StartsWith(ptx, sc));
314314
}
315315

316-
public static LogEventPropertyValue? EndsWith(StringComparison sc, LogEventPropertyValue? value, LogEventPropertyValue? substring)
316+
public static LogEventPropertyValue? EndsWith(StringComparison sc, LogEventPropertyValue? haystack, LogEventPropertyValue? needle)
317317
{
318-
if (!Coerce.String(value, out var ctx) ||
319-
!Coerce.String(substring, out var ptx))
318+
if (!Coerce.String(haystack, out var ctx) ||
319+
!Coerce.String(needle, out var ptx))
320320
return null;
321321

322322
return ScalarBoolean(ctx.EndsWith(ptx, sc));
@@ -327,10 +327,10 @@ public static LogEventPropertyValue IsDefined(LogEventPropertyValue? value)
327327
return ScalarBoolean(value != null);
328328
}
329329

330-
public static LogEventPropertyValue? ElementAt(StringComparison sc, LogEventPropertyValue? items, LogEventPropertyValue? index)
330+
public static LogEventPropertyValue? ElementAt(StringComparison sc, LogEventPropertyValue? collection, LogEventPropertyValue? index)
331331
{
332332
// ReSharper disable once ConvertIfStatementToSwitchStatement
333-
if (items is SequenceValue arr && Coerce.Numeric(index, out var ix))
333+
if (collection is SequenceValue arr && Coerce.Numeric(index, out var ix))
334334
{
335335
if (ix != Math.Floor(ix))
336336
return null;
@@ -342,12 +342,12 @@ public static LogEventPropertyValue IsDefined(LogEventPropertyValue? value)
342342
return arr.Elements.ElementAt(idx);
343343
}
344344

345-
if (items is StructureValue st && Coerce.String(index, out var s))
345+
if (collection is StructureValue st && Coerce.String(index, out var s))
346346
{
347347
return Intrinsics.TryGetStructurePropertyValue(sc, st, s);
348348
}
349349

350-
if (items is DictionaryValue dict && index is ScalarValue sv)
350+
if (collection is DictionaryValue dict && index is ScalarValue sv)
351351
{
352352
// The lack of eager numeric type coercion means that here, `sv` may logically equal one
353353
// of the keys, but not be equal according to the dictionary's `IEqualityComparer`.
@@ -359,45 +359,45 @@ public static LogEventPropertyValue IsDefined(LogEventPropertyValue? value)
359359
return null;
360360
}
361361

362-
public static LogEventPropertyValue? _Internal_Any(LogEventPropertyValue? items, LogEventPropertyValue? predicate)
362+
public static LogEventPropertyValue? _Internal_Any(LogEventPropertyValue? collection, LogEventPropertyValue? predicate)
363363
{
364364
if (!Coerce.Predicate(predicate, out var pred))
365365
return null;
366366

367-
if (items is SequenceValue arr)
367+
if (collection is SequenceValue arr)
368368
{
369369
return ScalarBoolean(arr.Elements.Any(e => Coerce.IsTrue(pred(e))));
370370
}
371371

372-
if (items is StructureValue structure)
372+
if (collection is StructureValue structure)
373373
{
374374
return ScalarBoolean(structure.Properties.Any(e => Coerce.IsTrue(pred(e.Value))));
375375
}
376376

377-
if (items is DictionaryValue dictionary)
377+
if (collection is DictionaryValue dictionary)
378378
{
379379
return ScalarBoolean(dictionary.Elements.Any(e => Coerce.IsTrue(pred(e.Value))));
380380
}
381381

382382
return null;
383383
}
384384

385-
public static LogEventPropertyValue? _Internal_All(LogEventPropertyValue? items, LogEventPropertyValue? predicate)
385+
public static LogEventPropertyValue? _Internal_All(LogEventPropertyValue? collection, LogEventPropertyValue? predicate)
386386
{
387387
if (!Coerce.Predicate(predicate, out var pred))
388388
return null;
389389

390-
if (items is SequenceValue arr)
390+
if (collection is SequenceValue arr)
391391
{
392392
return ScalarBoolean(arr.Elements.All(e => Coerce.IsTrue(pred(e))));
393393
}
394394

395-
if (items is StructureValue structure)
395+
if (collection is StructureValue structure)
396396
{
397397
return ScalarBoolean(structure.Properties.All(e => Coerce.IsTrue(pred(e.Value))));
398398
}
399399

400-
if (items is DictionaryValue dictionary)
400+
if (collection is DictionaryValue dictionary)
401401
{
402402
return ScalarBoolean(dictionary.Elements.All(e => Coerce.IsTrue(pred(e.Value))));
403403
}
@@ -451,9 +451,9 @@ public static LogEventPropertyValue _Internal_IsNotNull(LogEventPropertyValue? v
451451
return value0;
452452
}
453453

454-
public static LogEventPropertyValue? Substring(LogEventPropertyValue? @string, LogEventPropertyValue? startIndex, LogEventPropertyValue? length = null)
454+
public static LogEventPropertyValue? Substring(LogEventPropertyValue? value, LogEventPropertyValue? startIndex, LogEventPropertyValue? length = null)
455455
{
456-
if (!Coerce.String(@string, out var str) ||
456+
if (!Coerce.String(value, out var str) ||
457457
!Coerce.Numeric(startIndex, out var si))
458458
return null;
459459

@@ -482,14 +482,24 @@ public static LogEventPropertyValue _Internal_IsNotNull(LogEventPropertyValue? v
482482
return null;
483483
}
484484

485+
public static LogEventPropertyValue? Replace(StringComparison sc, LogEventPropertyValue? haystack, LogEventPropertyValue? needle, LogEventPropertyValue? replacement)
486+
{
487+
if (Coerce.String(haystack, out var h) && Coerce.String(needle, out var n) && Coerce.String(replacement, out var r))
488+
{
489+
return new ScalarValue(h.Replace(n, r, sc));
490+
}
491+
492+
return null;
493+
}
494+
485495
// ReSharper disable once ReturnTypeCanBeNotNullable
486-
public static LogEventPropertyValue? IndexOfMatch(StringComparison sc, LogEventPropertyValue? corpus, LogEventPropertyValue? regex)
496+
public static LogEventPropertyValue? IndexOfMatch(StringComparison sc, LogEventPropertyValue? haystack, LogEventPropertyValue? needle)
487497
{
488498
throw new InvalidOperationException("Regular expression evaluation is intrinsic.");
489499
}
490500

491501
// ReSharper disable once ReturnTypeCanBeNotNullable
492-
public static LogEventPropertyValue? IsMatch(StringComparison sc, LogEventPropertyValue? corpus, LogEventPropertyValue? regex)
502+
public static LogEventPropertyValue? IsMatch(StringComparison sc, LogEventPropertyValue? haystack, LogEventPropertyValue? needle)
493503
{
494504
throw new InvalidOperationException("Regular expression evaluation is intrinsic.");
495505
}

0 commit comments

Comments
 (0)