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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! A simple console example that lets the user pick from a few different
//! scenarios that have set configurations that are relevant to the scenario.
//! This is meant to be a quick way to see how different configurations can be
//! used in different contexts within the same project.
//! Run with: `cargo run --example console_entry_config`
use std::io::{self, BufRead, Write};
use partial_date::models::{
Century, ComponentOrder, Config, DateComponent, DayConfig, IsExpected, MonthConfig,
SlidingWindowPivot, TwoDigitYearExpansion, YearConfig,
};
fn main() {
println!("Partial Date Extraction Examples");
println!("===============================\n");
println!("Welcome to this interactive console example of how the library can be used!");
let stdin = io::stdin();
let mut stdout = io::stdout();
'scenario: loop {
println!("Select a scenario:");
println!(" 1) StrictDMY");
println!(" 2) AllHistoricalDates");
println!(" 3) IndustrialRevolutionDates");
println!(" 4) ChildrenBirthdays");
println!(" (quit to exit)");
print!("> ");
stdout.flush().unwrap();
let mut choice = String::new();
stdin.lock().read_line(&mut choice).unwrap();
let config_preset = match choice.trim() {
"1" => PreDefinedConfigs::StrictDMY,
"2" => PreDefinedConfigs::AllHistoricalDates,
"3" => PreDefinedConfigs::IndustrialRevolutionDates,
"4" => PreDefinedConfigs::ChildrenBirthdays,
"quit" => break 'scenario,
_ => {
println!("Unknown option.\n");
continue 'scenario;
}
};
loop {
print!("Enter a date (or 'back' / 'quit'): ");
stdout.flush().unwrap();
let mut input = String::new();
stdin.lock().read_line(&mut input).unwrap();
match input.trim() {
"quit" => break 'scenario,
"back" => break,
text => {
let result = partial_date::extract::extract(partial_date::models::Input {
utterance: text.to_string(),
config: Some(config_preset.get_config()),
});
println!(" Day: {:?}", result.day.value);
println!(" Month: {:?}", result.month.number);
println!(" Year: {:?}\n", result.year.value);
}
}
}
}
println!("Goodbye!");
}
pub enum PreDefinedConfigs {
StrictDMY,
AllHistoricalDates,
IndustrialRevolutionDates,
ChildrenBirthdays,
}
impl PreDefinedConfigs {
pub fn get_config(&self) -> Config {
match self {
// Strictly day-first numeric dates with all three components
// required. Letter-O substitution is disabled since this scenario
// expects clean numeric input only.
PreDefinedConfigs::StrictDMY => Config::default()
.with_day(
DayConfig::default()
.with_expected(IsExpected::Yes),
)
.with_month(
MonthConfig::default()
.with_expected(IsExpected::Yes)
)
.with_year(
YearConfig::default()
.with_range(1, 3000)
.with_expected(IsExpected::Yes)
.with_two_digit_expansion(TwoDigitYearExpansion::Literal),
)
.with_component_order(
ComponentOrder::new(
DateComponent::Day,
DateComponent::Month,
DateComponent::Year,
)
.unwrap(),
)
.with_letter_o_substitution(false),
// Wide ranging historical dates that cannot use 2-digit year
// expansion as there is no way to know which centuries the dates
// will be from. Minimal assumptions about the data when there is
// a lot of uncertainty.
PreDefinedConfigs::AllHistoricalDates => Config::default().with_year(
YearConfig::default()
.with_range(1, 3000)
.with_expected(IsExpected::Yes)
.with_two_digit_expansion(TwoDigitYearExpansion::Literal),
),
// Constrains the year range to the Industrial Revolution period and
// uses a sliding window for 2-digit years centred on 1800.
// Component order matches Great Britain's common DD/MM/YYYY format.
PreDefinedConfigs::IndustrialRevolutionDates => Config::default()
.with_year(
YearConfig::default()
.with_range(1760, 1840)
.with_expected(IsExpected::Yes)
.with_two_digit_expansion(TwoDigitYearExpansion::SlidingWindow {
earliest_year: 1750,
pivot: SlidingWindowPivot::new(50),
}),
)
.with_component_order(
ComponentOrder::new(
DateComponent::Day,
DateComponent::Month,
DateComponent::Year,
)
.unwrap(),
),
// Children under 18 — birth years must be in the 2000s and not in
// the future. Always(Century(2000)) maps all 2-digit values to the
// 2000s; the max of 2026 rejects future years.
PreDefinedConfigs::ChildrenBirthdays => Config::default().with_year(
YearConfig::default()
.with_range(2000, 2026)
.with_expected(IsExpected::Yes)
.with_two_digit_expansion(TwoDigitYearExpansion::Always(Century::new(2000)))
.with_single_digit_expansion(true),
),
}
}
}