Skip to content

Commit d938b2a

Browse files
committed
Added deduction.
1 parent 3ada806 commit d938b2a

9 files changed

Lines changed: 293 additions & 267 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,8 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
## [1.1.0] - 26-09-2025
5+
## [0.1.0] - 2025-10-02
66

7-
- Added `MatchMode` enum to support exact matching in `TextMatcher`, with the default being `MatchMode.Fuzzy` for fuzzy searching.
8-
9-
## [0.2.1] - 26-09-2025
10-
11-
- Fixed a bug where using ignore-case comparisons would return match values in uppercase.
12-
13-
## [0.2.0] - 26-09-2025
14-
15-
- Added optional `StringComparison` support for `TextMatcher`, with the default being `StringComparison.CurrentCulture` if not specified.
7+
- Initial release.
8+
- Implemented `add` expression to shift a base `DateTime` by an amount.
9+
- Implemented `deduct`/`subtract` expression to shift a base `DateTime` backwards by an amount.

README.md

Lines changed: 43 additions & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -1,263 +1,92 @@
11
# ![Icon](logo.png)
2-
![NuGet Version](https://img.shields.io/nuget/v/Flint)
2+
![NuGet Version](https://img.shields.io/nuget/v/STYME)
33

4-
Flint is a lightweight, zero-dependency C# library that provides fast text matching utilities using the [Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm).
4+
STYME is a lightweight, zero-dependency C# library for parsing simple natural-language date/time expressions and applying them to a base date/time.
55

66
## Usage Examples
77

88
### Basic
99

1010
```csharp
11-
using Flint;
11+
using STYME;
1212

13-
var matcher = new TextMatcher(new[] { "cat", "dog" });
14-
var results = matcher.Find("The dog chased the cat.");
15-
16-
foreach (var match in results)
17-
{
18-
Console.WriteLine($"Found '{match.Value}' at index {match.StartIndex}.");
19-
}
20-
```
21-
22-
Output:
23-
24-
```
25-
Found 'dog' at index 4.
26-
Found 'cat' at index 19.
27-
```
28-
29-
An optional ```StringComparison``` can be passed to ```TextMatcher```, influencing it's behavior when performing searches/replacement.
30-
If none is given, it will default to ```StringComparison.CurrentCulture```.
31-
32-
```csharp
33-
using Flint;
34-
35-
var matcher = new TextMatcher(new[] { "cat", "dog" }, StringComparison.OrdinalIgnoreCase);
36-
var results = matcher.Find("The DOG chased the CaT.");
37-
38-
foreach (var match in results)
39-
{
40-
Console.WriteLine($"Found '{match.Value}' at index {match.StartIndex}.");
41-
}
13+
// By default NaturalDateTime uses the current system time as the base
14+
var parser = new NaturalDateTime();
15+
var result = parser.Parse("add 2 days");
16+
Console.WriteLine(result);
4217
```
4318

44-
Output:
19+
Output (example):
4520

4621
```
47-
Found 'DOG' at index 4.
48-
Found 'CaT' at index 19.
22+
2025-10-04T14:23:00
4923
```
5024

51-
### Find with a callback
52-
53-
`TextMatcher` provides an overload of `Find` that accepts a callback invoked for each match. This can be convenient to process matches as they are found without allocating a results collection.
25+
You can also parse expressions relative to a specific `DateTime` using `NaturalDateTime.From`.
5426

5527
```csharp
56-
using Flint;
28+
using STYME;
5729

58-
var matcher = new TextMatcher(new[] { "cat", "dog" });
59-
matcher.Find("The dog chased the cat.", match =>
60-
{
61-
Console.WriteLine($"Found '{match.Value}' at index {match.StartIndex}.");
62-
});
30+
var baseTime = new DateTime(2020, 1, 1, 0, 0, 0);
31+
var parser = NaturalDateTime.From(baseTime);
32+
var result = parser.Parse("add 1 month");
33+
Console.WriteLine(result);
6334
```
6435

6536
Output:
6637

6738
```
68-
Found 'dog' at index 4.
69-
Found 'cat' at index 19.
70-
```
71-
72-
### Scan multiple texts with `FindAll`
73-
74-
```csharp
75-
using Flint;
76-
77-
var patterns = new[] { "cat", "dog", "bird" };
78-
var matcher = new TextMatcher(patterns);
79-
80-
var texts = new[]
81-
{
82-
"The dog chased the cat.",
83-
"A bird watched them from above.",
84-
"No animals here."
85-
};
86-
87-
var all = matcher.FindAll(texts);
88-
89-
foreach (var kv in all)
90-
{
91-
Console.WriteLine(kv.Key);
92-
foreach (var m in kv.Value)
93-
{
94-
Console.WriteLine($"Found '{m.Value}' at index {m.StartIndex}.");
95-
}
96-
}
97-
```
98-
99-
Example output:
100-
101-
```
102-
The dog chased the cat.
103-
Found 'cat' at index 19.
104-
Found 'dog' at index 4.
105-
A bird watched them from above.
106-
Found 'bird' at index 2.
107-
No animals here.
108-
```
109-
110-
If you need to scan many input strings and handle matches as they are discovered, use the `FindAll` overload that accepts an `Action<string, Match>` callback. The callback receives the original text and the match.
111-
112-
```csharp
113-
using Flint;
114-
115-
var patterns = new[] { "cat", "dog" };
116-
var matcher = new TextMatcher(patterns);
117-
118-
var texts = new[]
119-
{
120-
"The dog chased the cat.",
121-
"A bird watched from above.",
122-
};
123-
124-
matcher.FindAll(texts, (text, match) =>
125-
{
126-
Console.WriteLine(text);
127-
Console.WriteLine($"Found '{match.Value}' at index {match.StartIndex}.");
128-
});
129-
```
130-
131-
Example output:
132-
133-
```
134-
The dog chased the cat.
135-
Found 'dog' at index 4.
136-
Found 'cat' at index 19.
137-
A bird watched from above.
138-
```
139-
140-
### Exact (whole-word) matching with `MatchMode`
141-
142-
The `MatchMode` enum lets you require matches to be whole words. This prevents short patterns from matching inside longer words (for example, preventing "he" from matching inside "she").
143-
144-
```csharp
145-
using Flint;
146-
147-
var patterns = new[] { "he", "she" };
148-
var matcher = new TextMatcher(patterns, StringComparison.CurrentCulture, MatchMode.ExactMatch);
149-
150-
var results = matcher.Find("she sells seashells.");
151-
152-
foreach (var m in results)
153-
{
154-
Console.WriteLine($"Found '{m.Value}' at index {m.StartIndex}.");
155-
}
156-
```
157-
158-
Output (only the whole-word `she` is matched):
159-
160-
```
161-
Found 'she' at index 0.
39+
2020-02-01T00:00:00
16240
```
16341

164-
### Overlapping and nested matches
42+
### Deduct / Subtract
16543

166-
```csharp
167-
using Flint;
168-
169-
var matcher = new TextMatcher(new[] { "he", "she", "his", "hers" });
170-
var results = matcher.Find("she is his hero");
171-
172-
foreach (var m in results)
173-
{
174-
Console.WriteLine($"Found '{m.Value}' at index {m.StartIndex}.");
175-
}
176-
```
177-
178-
Example output:
179-
180-
```
181-
Found 'she' at index 0.
182-
Found 'he' at index 1.
183-
Found 'his' at index 7.
184-
Found 'he' at index 10.
185-
```
186-
187-
### Replace all matches with a single value
44+
You can subtract time using the `deduct` (or `subtract`) keyword. The expression works the same as `add` but shifts the base time backwards.
18845

18946
```csharp
190-
using Flint;
47+
using STYME;
19148

192-
var matcher = new TextMatcher(new[] { "cat", "dog" });
193-
var replaced = matcher.Replace("The dog chased the cat.", "animal");
194-
Console.WriteLine(replaced);
49+
var baseTime = new DateTime(2020, 3, 1, 12, 0, 0);
50+
var parser = NaturalDateTime.From(baseTime);
51+
var result = parser.Parse("deduct 1 month");
52+
Console.WriteLine(result);
19553
```
19654

19755
Output:
19856

19957
```
200-
The animal chased the animal.
58+
2020-02-01T12:00:00
20159
```
20260

203-
### Replace matches using a function
61+
### Supported units with `add` and `deduct`
20462

205-
```csharp
206-
using Flint;
63+
The `add` and `deduct` expressions support the following units (singular and plural forms):
20764

208-
var matcher = new TextMatcher(new[] { "cat", "dog" });
209-
var replaced = matcher.Replace(
210-
"The dog chased the cat.",
211-
match => match.Value.ToUpper()
212-
);
213-
Console.WriteLine(replaced);
214-
```
215-
216-
Output:
217-
218-
```
219-
The DOG chased the CAT.
220-
```
65+
- `second`, `seconds`
66+
- `minute`, `minutes`
67+
- `hour`, `hours`
68+
- `day`, `days`
69+
- `week`, `weeks`
70+
- `month`, `months`
71+
- `year`, `years`
72+
- `decade`, `decades`
73+
- `century`, `centuries`
74+
- `millennium`, `millennia`
22175

222-
### Replace each pattern with a different value
76+
Example:
22377

22478
```csharp
225-
using Flint;
226-
227-
var matcher = new TextMatcher(new[] { "cat", "dog" });
228-
var replaced = matcher.Replace(
229-
"The dog chased the cat.",
230-
new[] { "feline", "canine" }
231-
);
232-
Console.WriteLine(replaced);
233-
```
234-
235-
Output:
236-
237-
```
238-
The canine chased the feline.
239-
```
240-
241-
### Load patterns from a file
242-
243-
```csharp
244-
using Flint;
245-
246-
var patterns = File.ReadAllLines("patterns.txt")
247-
.Where(l => !string.IsNullOrWhiteSpace(l));
248-
249-
var matcher = new TextMatcher(patterns);
250-
251-
var text = File.ReadAllText("large_input.txt");
252-
var hits = matcher.Find(text).ToArray();
79+
using STYME;
25380

254-
Console.WriteLine($"Found {hits.Length} matches.");
81+
var parser = NaturalDateTime.From(new DateTime(2000, 1, 1));
82+
Console.WriteLine(parser.Parse("add 2 decades")); // 2020-01-01
83+
Console.WriteLine(parser.Parse("deduct 1 century")); // 1900-01-01
25584
```
25685

25786
## Support
25887

259-
* .NET Standard 2.0 and .NET 8.0
88+
* .NET 8.0 and later
26089

26190
## License
26291

263-
Flint is licensed under the [MIT License](LICENSE).
92+
STYME is licensed under the [MIT License](LICENSE).

STYME.slnx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<Solution>
22
<Folder Name="/Solution Items/">
3+
<File Path="CHANGELOG.md" />
34
<File Path="Directory.Packages.props" />
5+
<File Path="README.md" />
46
</Folder>
57
<Project Path="src/STYME.UnitTests/STYME.UnitTests.csproj" Id="2dc125cf-fb41-4adc-b8d7-48e2122ceec9" />
68
<Project Path="src/STYME/STYME.csproj" />

0 commit comments

Comments
 (0)