📄
src/JsonLdRecipeParser/Ingredient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using System; using System.Buffers; using System.Diagnostics.CodeAnalysis; using JsonLdRecipeParser.Json; namespace JsonLdRecipeParser; public record Ingredient { private static readonly SearchValues<char> WhitespaceCharacters = SearchValues.Create(" \t"); public required string Name { get; set; } public Amount? Amount { get; set; } internal static Ingredient? From(RecipeIngredient ingredient) => ingredient.Value switch { string text => TryParse(text, out var i) ? i : null, _ => throw new NotImplementedException("Ingredient parsing is only implemented for strings."), }; public static bool TryParse(string text, [NotNullWhen(true)] out Ingredient? ingredient) { var span = text.AsSpan(); _ = Amount.TryParse(ref span, out var amount); if (TryParseIngredient(ref span, out var name)) { ingredient = new() { Name = name, Amount = amount }; return true; } if (amount?.Unit is string unitName) { ingredient = new() { Name = unitName, Amount = amount with { Unit = null } }; return true; } ingredient = default; return false; } private static bool TryParseIngredient(ref ReadOnlySpan<char> text, [NotNullWhen(true)] out string? name) { var start = text.IndexOfAnyExcept(WhitespaceCharacters); if (start == -1) { name = default; return false; } text = text[start..]; var end = text.LastIndexOfAnyExcept(WhitespaceCharacters); if (end == -1) { end = text.Length; } end += 1; name = text[..end].ToString(); text = text[end..]; return true; } }