FormFlow/Recognize.cs
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license.
4 //
5 // Microsoft Bot Framework: http://botframework.com
6 //
7 // Bot Builder SDK GitHub:
8 // https://github.com/Microsoft/BotBuilder
9 //
10 // Copyright (c) Microsoft Corporation
11 // All rights reserved.
12 //
13 // MIT License:
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 
34 using System;
35 using System.Collections.Generic;
36 using System.Globalization;
37 using System.Linq;
38 using System.Text;
39 using System.Text.RegularExpressions;
40 using Chronic;
41 using System.Threading;
42 
43 namespace Microsoft.Bot.Builder.FormFlow.Advanced
44 {
48  public sealed class RecognizeEnumeration<T> : IRecognize<T>
49  where T : class
50  {
56  public delegate DescribeAttribute DescriptionDelegate(object value);
57 
63  public delegate IEnumerable<string> TermsDelegate(object value);
64 
70  {
71  _form = field.Form;
72  _allowNumbers = field.AllowNumbers;
73  _description = field.FieldDescription.Description;
74  _terms = field.FieldTerms.ToArray();
75  _values = field.Values.ToArray();
76  _valueDescriptions = field.ValueDescriptions.ToArray();
77  _descriptionDelegate = (value) => field.ValueDescription(value);
78  _termsDelegate = (value) => field.Terms(value);
79  _helpFormat = field.Template(field.AllowNumbers
80  ? (field.AllowsMultiple ? TemplateUsage.EnumManyNumberHelp : TemplateUsage.EnumOneNumberHelp)
81  : (field.AllowsMultiple ? TemplateUsage.EnumManyWordHelp : TemplateUsage.EnumOneWordHelp));
82  _noPreference = field.Optional ? field.Form.Configuration.NoPreference : null;
83  _currentChoice = field.Form.Configuration.CurrentChoice.FirstOrDefault();
84  BuildPerValueMatcher(from term in field.Form.Configuration.CurrentChoice select Regex.Escape(term.Trim()).Replace(" ", @"\s+"));
85  }
86 
87  public object[] PromptArgs()
88  {
89  return new object[0];
90  }
91 
92  public IEnumerable<object> Values()
93  {
94  return _values;
95  }
96 
97  public IEnumerable<DescribeAttribute> ValueDescriptions()
98  {
99  return _valueDescriptions;
100  }
101 
102  public DescribeAttribute ValueDescription(object value)
103  {
104  return _descriptionDelegate(value);
105  }
106 
107  public IEnumerable<string> ValidInputs(object value)
108  {
109  return _termsDelegate(value);
110  }
111 
112  public string Help(T state, object defaultValue)
113  {
114  var values = (from val in _valueDescriptions select val.Description);
115  var max = _max;
116  if (_noPreference != null)
117  {
118  values = values.Union(new string[] { _noPreference.First() });
119  if (defaultValue == null)
120  {
121  --max;
122  }
123  }
124  if ((defaultValue != null || _noPreference != null) && _currentChoice != null)
125  {
126  values = values.Union(new string[] { _currentChoice });
127  }
128  var args = new List<object>();
129  if (_allowNumbers)
130  {
131  args.Add(1);
132  args.Add(max);
133  }
134  else
135  {
136  args.Add(null);
137  args.Add(null);
138  }
139  args.Add(Language.BuildList(from val in values select Language.Normalize(val, _helpFormat.ChoiceCase), _helpFormat.ChoiceSeparator, _helpFormat.ChoiceLastSeparator));
140  return new Prompter<T>(_helpFormat, _form, this).Prompt(state, null, args.ToArray()).Prompt;
141  }
142 
143  public IEnumerable<TermMatch> Matches(string input, object defaultValue)
144  {
145  // if the user hit enter on an optional prompt, then consider taking the current choice as a low confidence option
146  bool userSkippedPrompt = string.IsNullOrWhiteSpace(input) && (defaultValue != null || _noPreference != null);
147  if (userSkippedPrompt)
148  {
149  yield return new TermMatch(0, input.Length, 1.0, defaultValue);
150  }
151 
152  foreach (var expression in _expressions)
153  {
154  double maxWords = expression.MaxWords;
155  foreach (Match match in expression.Expression.Matches(input))
156  {
157  var group1 = match.Groups[1];
158  var group2 = match.Groups[2];
159  object newValue;
160  if (group1.Success)
161  {
162  if (ConvertSpecial(expression.Value, defaultValue, out newValue))
163  {
164  yield return new TermMatch(group1.Index, group1.Length, 1.0, newValue);
165  }
166  }
167  if (group2.Success)
168  {
169  var words = group2.Value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
170  var confidence = System.Math.Min(words / maxWords, 1.0);
171  if (ConvertSpecial(expression.Value, defaultValue, out newValue))
172  {
173  yield return new TermMatch(group2.Index, group2.Length, confidence, newValue);
174  }
175  }
176  }
177  }
178  }
179 
180  public override string ToString()
181  {
182  var builder = new StringBuilder();
183  builder.AppendFormat("RecognizeEnumeration({0}", _description);
184  builder.Append(" [");
185  foreach (var description in _valueDescriptions)
186  {
187  builder.Append(" ");
188  builder.Append(description);
189  }
190  builder.Append("])");
191  return builder.ToString();
192  }
193 
194  private enum Special { CurrentChoice, NoPreference };
195 
196  // Word character, any word character, any digit, any positive group over word characters
197  private const string WORD = @"(\w|\\w|\\d|(\[(?>(\w|-)+|\[(?<number>)|\](?<-number>))*(?(number)(?!))\]))";
198  // Starts with matching word character
199  private static Regex _wordStart = new Regex($@"^{WORD}", RegexOptions.Compiled);
200  // Ends with matching word character with optional repetitions
201  private static Regex _wordEnd = new Regex($@"{WORD}(\?|\*|\+|\{{\d+\}}|\{{,\d+\}}|\{{\d+,\d+\}})?$", RegexOptions.Compiled);
202 
203  private void BuildPerValueMatcher(IEnumerable<string> currentChoice)
204  {
205  if (currentChoice != null)
206  {
207  // 0 is reserved for current default if any
208  AddExpression(0, Special.CurrentChoice, currentChoice, _allowNumbers);
209  }
210  var n = 1;
211  foreach (var value in _values)
212  {
213  n = AddExpression(n, value, _termsDelegate(value), _allowNumbers);
214  }
215  if (_noPreference != null)
216  {
217  // Add recognizer for no preference
218  n = AddExpression(n, Special.NoPreference, _noPreference, _allowNumbers);
219  }
220  if (_terms != null && _terms.Count() > 0)
221  {
222  // Add field terms to help disambiguate
223  AddExpression(n, SpecialValues.Field, _terms, false);
224  }
225  _max = n - 1;
226  }
227 
228  private int NumberOfWords(string regex)
229  {
230  return regex.Split(new string[] { @"\s", " " }, StringSplitOptions.RemoveEmptyEntries).Length;
231  }
232 
233  // Generate a regex with 3 parts:
234  // Group 1: startWord <number> endWord
235  // Group 2: (all word terms) with optional start/end words
236  // If a group is empty, match on NOMATCH constant.
237  private const string NOMATCH = "__qqqq__";
238  private int AddExpression(int n, object value, IEnumerable<string> terms, bool allowNumbers)
239  {
240  var orderedTerms = (from term in terms orderby term.Length descending select term).ToArray();
241  var words = new StringBuilder();
242  var first = true;
243  int maxWords = 0;
244  if (orderedTerms.Length > 0)
245  {
246  maxWords = terms.Max(NumberOfWords);
247  foreach (var term in orderedTerms)
248  {
249  var nterm = term.Trim().Replace(" ", @"\s+");
250  if (nterm != "")
251  {
252  if (first)
253  {
254  first = false;
255  words.Append('(');
256  }
257  else
258  {
259  words.Append('|');
260  }
261  words.Append("(?:");
262  if (_wordStart.Match(nterm).Success && _wordEnd.Match(nterm).Success)
263  {
264  words.Append($@"\b{nterm}\b");
265  }
266  else
267  {
268  words.Append(nterm);
269  }
270  words.Append(')');
271  }
272  }
273  }
274  if (first)
275  {
276  words.Append($@"(\b(?:{NOMATCH})");
277  }
278  words.Append(')');
279  var numbers = allowNumbers ? $"(\\b{n}\\b)" : NOMATCH;
280  var expr = $"{numbers}|{words}";
281  _expressions.Add(new ValueAndExpression(value, new Regex(expr.ToString(), RegexOptions.IgnoreCase), maxWords));
282  ++n;
283  return n;
284  }
285 
286  private bool ConvertSpecial(object value, object defaultValue, out object newValue)
287  {
288  bool ok = true;
289  newValue = value;
290  if (value is Special)
291  {
292  var special = (Special)value;
293  if (special == Special.CurrentChoice && (_noPreference != null || defaultValue != null))
294  {
295  newValue = defaultValue;
296  }
297  else if (special == Special.NoPreference)
298  {
299  newValue = null;
300  }
301  else
302  {
303  ok = false;
304  }
305  }
306  return ok;
307  }
308 
309  private class ValueAndExpression
310  {
311  public ValueAndExpression(object value, Regex expression, int maxWords)
312  {
313  Value = value;
314  Expression = expression;
315  MaxWords = maxWords;
316  }
317 
318  public readonly object Value;
319  public readonly Regex Expression;
320  public readonly int MaxWords;
321  }
322 
323  private readonly IForm<T> _form;
324  private readonly string _description;
325  private readonly IEnumerable<string> _noPreference;
326  private readonly string _currentChoice;
327  private readonly bool _allowNumbers;
328  private readonly IEnumerable<string> _terms;
329  private readonly IEnumerable<object> _values;
330  private readonly IEnumerable<DescribeAttribute> _valueDescriptions;
331  private readonly DescriptionDelegate _descriptionDelegate;
332  private readonly TermsDelegate _termsDelegate;
333  private readonly TemplateAttribute _helpFormat;
334  private int _max;
335  private readonly List<ValueAndExpression> _expressions = new List<ValueAndExpression>();
336  }
337 
342  public abstract class RecognizePrimitive<T> : IRecognize<T>
343  where T : class
344  {
345 
351  {
352  _field = field;
353  _currentChoices = new HashSet<string>(from choice in field.Form.Configuration.CurrentChoice
354  select choice.Trim().ToLower());
355  if (field.Optional)
356  {
357  if (field.IsNullable)
358  {
359  _noPreference = new HashSet<string>(from choice in field.Form.Configuration.NoPreference
360  select choice.Trim().ToLower());
361  }
362  else
363  {
364  throw new ArgumentException("Primitive values must be nullable to be optional.");
365  }
366  }
367  }
368 
369  public virtual object[] PromptArgs()
370  {
371  return new object[0];
372  }
373 
379  public abstract TermMatch Parse(string input);
380 
381  public virtual IEnumerable<TermMatch> Matches(string input, object defaultValue = null)
382  {
383  var matchValue = input.Trim().ToLower();
384  if (_noPreference != null && _noPreference.Contains(matchValue))
385  {
386  yield return new TermMatch(0, input.Length, 1.0, null);
387  }
388  else if ((defaultValue != null || _noPreference != null) && (matchValue == "" || _currentChoices.Contains(matchValue)))
389  {
390  yield return new TermMatch(0, input.Length, 1.0, defaultValue);
391  }
392  else
393  {
394  var result = Parse(input);
395  if (result != null)
396  {
397  yield return result;
398  }
399  }
400  }
401 
402  public abstract IEnumerable<string> ValidInputs(object value);
403 
404  public abstract DescribeAttribute ValueDescription(object value);
405 
406  public virtual IEnumerable<DescribeAttribute> ValueDescriptions()
407  {
408  return new DescribeAttribute[0];
409  }
410 
411  public virtual IEnumerable<object> Values()
412  {
413  return null;
414  }
415 
416  public abstract string Help(T state, object defaultValue);
417 
424  protected List<object> HelpArgs(T state, object defaultValue)
425  {
426  var args = new List<object>();
427  if (defaultValue != null || _field.Optional)
428  {
429  args.Add(_field.Form.Configuration.CurrentChoice.First());
430  if (_field.Optional)
431  {
432  args.Add(_field.Form.Configuration.NoPreference.First());
433  }
434  else
435  {
436  args.Add(null);
437  }
438  }
439  else
440  {
441  args.Add(null);
442  args.Add(null);
443  }
444  return args;
445  }
446 
450  protected IField<T> _field;
451 
452  private HashSet<string> _currentChoices;
453  private HashSet<string> _noPreference;
454  }
455 
460  public sealed class RecognizeBool<T> : RecognizePrimitive<T>
461  where T : class
462  {
467  public RecognizeBool(IField<T> field)
468  : base(field)
469  {
470  _yes = new HashSet<string>(from term in field.Form.Configuration.Yes
471  select term.Trim().ToLower());
472  _no = new HashSet<string>(from term in field.Form.Configuration.No
473  select term.Trim().ToLower());
474  }
475 
476  public override TermMatch Parse(string input)
477  {
478  TermMatch result = null;
479  var matchValue = input.Trim().ToLower();
480  if (_yes.Contains(matchValue))
481  {
482  result = new TermMatch(0, input.Length, 1.0, true);
483  }
484  else if (_no.Contains(matchValue))
485  {
486  result = new TermMatch(0, input.Length, 1.0, false);
487  }
488  return result;
489  }
490 
491  public override string Help(T state, object defaultValue)
492  {
493  var prompt = new Prompter<T>(_field.Template(TemplateUsage.BoolHelp), _field.Form, null);
494  var args = HelpArgs(state, defaultValue);
495  return prompt.Prompt(state, _field, args.ToArray()).Prompt;
496  }
497 
498  public override IEnumerable<string> ValidInputs(object value)
499  {
500  return (bool)value
501  ? _field.Form.Configuration.Yes
502  : _field.Form.Configuration.No;
503  }
504 
505  public override DescribeAttribute ValueDescription(object value)
506  {
507  return new DescribeAttribute(((bool)value
508  ? _field.Form.Configuration.Yes
509  : _field.Form.Configuration.No).First());
510  }
511 
512  public override IEnumerable<DescribeAttribute> ValueDescriptions()
513  {
514  return new DescribeAttribute[] { ValueDescription(true), ValueDescription(false) };
515  }
516 
517  private HashSet<string> _yes;
518  private HashSet<string> _no;
519  }
520 
525  public sealed class RecognizeString<T> : RecognizePrimitive<T>
526  where T : class
527  {
533  : base(field)
534  {
535  }
536 
537  public override IEnumerable<string> ValidInputs(object value)
538  {
539  yield return (string)value;
540  }
541 
542  public override DescribeAttribute ValueDescription(object value)
543  {
544  return new DescribeAttribute((string)value);
545  }
546 
547  public override TermMatch Parse(string input)
548  {
549  TermMatch result = null;
550  if (!string.IsNullOrWhiteSpace(input))
551  {
552  // Confidence is 0.0 so commands get a crack
553  result = new TermMatch(0, input.Length, 0.0, input);
554  }
555  return result;
556  }
557 
558  public override string Help(T state, object defaultValue)
559  {
560  var prompt = new Prompter<T>(_field.Template(TemplateUsage.StringHelp), _field.Form, null);
561  var args = HelpArgs(state, defaultValue);
562  return prompt.Prompt(state, _field, args.ToArray()).Prompt;
563  }
564  }
565 
570  public sealed class RecognizeNumber<T> : RecognizePrimitive<T>
571  where T : class
572  {
578  : base(field)
579  {
580  double min, max;
581  _showLimits = field.Limits(out min, out max);
582  _min = (long)min;
583  _max = (long)max;
584  }
585 
586  public override object[] PromptArgs()
587  {
588  return _showLimits ? new object[] { _min, _max } : new object[] { null, null };
589  }
590 
591  public override DescribeAttribute ValueDescription(object value)
592  {
593  return new DescribeAttribute(((long)Convert.ChangeType(value, typeof(long))).ToString(Thread.CurrentThread.CurrentUICulture.NumberFormat));
594  }
595 
596  public override IEnumerable<string> ValidInputs(object value)
597  {
598  yield return ((long)value).ToString(Thread.CurrentThread.CurrentUICulture.NumberFormat);
599  }
600 
601  public override TermMatch Parse(string input)
602  {
603  TermMatch result = null;
604  long number;
605  if (long.TryParse(input, NumberStyles.Integer, Thread.CurrentThread.CurrentUICulture.NumberFormat, out number))
606  {
607  if (number >= _min && number <= _max)
608  {
609  result = new TermMatch(0, input.Length, 1.0, number);
610  }
611  }
612  return result;
613  }
614 
615  public override string Help(T state, object defaultValue)
616  {
617  var prompt = new Prompter<T>(_field.Template(TemplateUsage.IntegerHelp), _field.Form, null);
618  var args = HelpArgs(state, defaultValue);
619  if (_showLimits)
620  {
621  args.Add(_min);
622  args.Add(_max);
623  }
624  return prompt.Prompt(state, _field, args.ToArray()).Prompt;
625  }
626 
627  private long _min;
628  private long _max;
629  private bool _showLimits;
630  }
631 
636  public sealed class RecognizeDouble<T> : RecognizePrimitive<T>
637  where T : class
638  {
639 
645  : base(field)
646  {
647  _showLimits = field.Limits(out _min, out _max);
648  }
649 
650  public override object[] PromptArgs()
651  {
652  return _showLimits ? new object[] { _min, _max } : new object[] { null, null };
653  }
654 
655  public override DescribeAttribute ValueDescription(object value)
656  {
657  return new DescribeAttribute(((double)Convert.ChangeType(value, typeof(double))).ToString(Thread.CurrentThread.CurrentUICulture.NumberFormat));
658  }
659 
660  public override IEnumerable<string> ValidInputs(object value)
661  {
662  yield return ((double)value).ToString(Thread.CurrentThread.CurrentUICulture.NumberFormat);
663  }
664 
665  public override TermMatch Parse(string input)
666  {
667  TermMatch result = null;
668  double number;
669  if (double.TryParse(input, NumberStyles.Float, Thread.CurrentThread.CurrentUICulture.NumberFormat, out number))
670  {
671  if (number >= _min && number <= _max)
672  {
673  result = new TermMatch(0, input.Length, 1.0, number);
674  }
675  }
676  return result;
677  }
678 
679  public override string Help(T state, object defaultValue)
680  {
681  var prompt = new Prompter<T>(_field.Template(TemplateUsage.DoubleHelp), _field.Form, null);
682  var args = HelpArgs(state, defaultValue);
683  if (_showLimits)
684  {
685  args.Add(_min);
686  args.Add(_max);
687  }
688  return prompt.Prompt(state, _field, args.ToArray()).Prompt;
689  }
690 
691  private double _min;
692  private double _max;
693  private bool _showLimits;
694  }
695 
704  public sealed class RecognizeDateTime<T> : RecognizePrimitive<T>
705  where T : class
706  {
712  : base(field)
713  {
714  _parser = new Chronic.Parser();
715  }
716 
717  public override string Help(T state, object defaultValue)
718  {
719  var prompt = new Prompter<T>(_field.Template(TemplateUsage.DateTimeHelp), _field.Form, null);
720  var args = HelpArgs(state, defaultValue);
721  return prompt.Prompt(state, _field, args.ToArray()).Prompt;
722  }
723 
724  public override TermMatch Parse(string input)
725  {
726  TermMatch match = null;
727  if (Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName != "en")
728  {
729  DateTime dt;
730  if (DateTime.TryParse(input, Thread.CurrentThread.CurrentUICulture.DateTimeFormat, DateTimeStyles.None, out dt))
731  {
732  match = new TermMatch(0, input.Length, 1.0, dt);
733  }
734  }
735  else
736  {
737  var parse = _parser.Parse(input);
738  if (parse != null && parse.Start.HasValue)
739  {
740  match = new TermMatch(0, input.Length, 1.0, parse.Start.Value);
741  }
742  }
743  return match;
744  }
745 
746  public override IEnumerable<string> ValidInputs(object value)
747  {
748  yield return ValueDescription(value).Description;
749  }
750 
751  public override DescribeAttribute ValueDescription(object value)
752  {
753  return new DescribeAttribute(((DateTime)value).ToString(Thread.CurrentThread.CurrentUICulture.DateTimeFormat));
754  }
755 
756  private Parser _parser;
757  }
758 }
override TermMatch Parse(string input)
Abstract method for parsing input.
override IEnumerable< string > ValidInputs(object value)
Return valid inputs to describe a particular value.
override DescribeAttribute ValueDescription(object value)
Return the description of a specific value.
RecognizeNumber(IField< T > field)
Construct a numeric recognizer for a field.
How to show no preference in an optional field.
IEnumerable< string > Terms(object value)
Given a value return terms that can be used in a dialog to match the object.
IEnumerable< object > Values
All possible values or null if it is a data type like number.
Definition: IField.cs:204
Define a template for generating strings.
Definition: Attributes.cs:571
override string Help(T state, object defaultValue)
Return the help string describing what are valid inputs to the recognizer.
IEnumerable< DescribeAttribute > ValueDescriptions
Return all possible value descriptions in order to support enumeration.
Definition: IField.cs:191
RecognizeDouble(IField< T > field)
Construct a double or float recognizer for a field.
override DescribeAttribute ValueDescription(object value)
Return the description of a specific value.
override TermMatch Parse(string input)
Abstract method for parsing input.
override object[] PromptArgs()
Return the arguments to pass to the prompt.
A prompt and recognizer packaged together.
Definition: IPrompt.cs:330
RecognizeBool(IField< T > field)
Construct a boolean recognizer for a field.
DescribeAttribute FieldDescription
Description of the field itself.
Definition: IField.cs:172
override object[] PromptArgs()
Return the arguments to pass to the prompt.
bool IsNullable
Test to see if field is nullable.
Definition: IField.cs:99
DescribeAttribute ValueDescription(object value)
Return the description of a specific value.
override IEnumerable< string > ValidInputs(object value)
Return valid inputs to describe a particular value.
RecognizeDateTime(IField< T > field)
Construct a date/time recognizer.
override DescribeAttribute ValueDescription(object value)
Return the description of a specific value.
bool AllowsMultiple
Are multiple matches allowed.
Definition: IField.cs:211
TemplateAttribute Template(TemplateUsage usage)
Return a template for building a prompt.
Interface for recognizers that look for matches in user input.
Definition: IRecognize.cs:159
TemplateUsage
All of the built-in templates.
Definition: Attributes.cs:321
override IEnumerable< string > ValidInputs(object value)
Return valid inputs to describe a particular value.
What to display when asked for help.
IEnumerable< TermMatch > Matches(string input, object defaultValue)
Return the matches found in the input.
Interface for all the information about a specific field.
Definition: IField.cs:404
Abstract class for constructing primitive value recognizers.
override TermMatch Parse(string input)
Abstract method for parsing input.
object[] PromptArgs()
Return the arguments to pass to the prompt.
RecognizePrimitive(IField< T > field)
Constructor using IField<T>.
override string Help(T state, object defaultValue)
Return the help string describing what are valid inputs to the recognizer.
IEnumerable< string > ValidInputs(object value)
Return valid inputs to describe a particular value.
FormPrompt Prompt(T state, IField< T > field, params object[] args)
Return prompt to send to user.
Definition: IPrompt.cs:357
Form definition interface.
Definition: IForm.cs:47
override string Help(T state, object defaultValue)
Return the help string describing what are valid inputs to the recognizer.
List< object > HelpArgs(T state, object defaultValue)
Return the help template args for current choice and no preference.
static string BuildList(IEnumerable< string > values, string separator, string lastSeparator)
Given a list of string values generate a proper English list.
Definition: Language.cs:283
override IEnumerable< string > ValidInputs(object value)
Return valid inputs to describe a particular value.
IEnumerable< string > FieldTerms
Terms for matching this field.
Definition: IField.cs:178
IEnumerable< object > Values()
Return all possible values or null if a primitive type.
RecognizeString(IField< T > field)
Construct a string recognizer for a field.
virtual object[] PromptArgs()
Return the arguments to pass to the prompt.
Field is used to get a value to set in the form state.
override TermMatch Parse(string input)
Abstract method for parsing input.
override DescribeAttribute ValueDescription(object value)
Return the description of a specific value.
override IEnumerable< DescribeAttribute > ValueDescriptions()
Return all possible value descriptions in order to support enumeration.
override TermMatch Parse(string input)
Abstract method for parsing input.
DescribeAttribute ValueDescription(object value)
Return the description of a specific value.
virtual IEnumerable< DescribeAttribute > ValueDescriptions()
Return all possible value descriptions in order to support enumeration.
virtual IEnumerable< object > Values()
Return all possible values or null if a primitive type.
SpecialValues
Enumeration of special kinds of matches.
Definition: IRecognize.cs:42
override DescribeAttribute ValueDescription(object value)
Return the description of a specific value.
string Help(T state, object defaultValue)
Return the help string describing what are valid inputs to the recognizer.
IForm< T > Form
Form that owns this field
Definition: IField.cs:420
bool Limits(out double min, out double max)
Limits of numeric values.
IField< T > _field
Field being filled information.
bool AllowNumbers
Allow user input to match numbers shown with enumerated choices.
Definition: IField.cs:223
RecognizeEnumeration(IField< T > field)
Constructor based on IField<T>.
bool Optional
Test to see if field is optional which means that an unknown value is legal.
Definition: IField.cs:93
override string Help(T state, object defaultValue)
Return the help string describing what are valid inputs to the recognizer.
override IEnumerable< string > ValidInputs(object value)
Return valid inputs to describe a particular value.
virtual IEnumerable< TermMatch > Matches(string input, object defaultValue=null)
Return the matches found in the input.
static string Normalize(string value, CaseNormalization normalization)
Normalize a string.
Definition: Language.cs:304
Describe a possible match in the user input.
Definition: IRecognize.cs:53
IEnumerable< DescribeAttribute > ValueDescriptions()
Return all possible value descriptions in order to support enumeration.
override string Help(T state, object defaultValue)
Return the help string describing what are valid inputs to the recognizer.
Attribute to override the default description of a field, property or enum value. ...
Definition: Attributes.cs:62