candidates.mojo (2881B)
1 from std.collections import List 2 3 4 @fieldwise_init 5 struct Candidate(Copyable, Movable): 6 var kind: String 7 var text: String 8 var start: Int 9 var end: Int 10 11 12 def _is_digit_byte(byte: UInt8) -> Bool: 13 return byte >= UInt8(ord("0")) and byte <= UInt8(ord("9")) 14 15 16 def _backward_number_start(text: String, unit_start: Int) -> Int: 17 var bytes = text.as_bytes() 18 var index = unit_start - 1 19 while index >= 0: 20 var byte = bytes[index] 21 if byte == UInt8(ord(" ")) or byte == UInt8(ord("\t")): 22 index -= 1 23 continue 24 break 25 var end = index 26 while index >= 0 and _is_digit_byte(bytes[index]): 27 index -= 1 28 if index == end: 29 return -1 30 return index + 1 31 32 33 def discover_candidates( 34 text: String, 35 known_products: List[String], 36 known_units: List[String], 37 known_dates: List[String], 38 ) -> List[Candidate]: 39 var candidates = List[Candidate]() 40 var lowered = text.lower() 41 42 for product in known_products: 43 if product.strip() == "": 44 continue 45 var index = lowered.find(product.lower()) 46 if index >= 0: 47 candidates.append( 48 Candidate( 49 kind="product", 50 text=String(product), 51 start=index, 52 end=index + product.byte_length(), 53 ) 54 ) 55 56 for unit in known_units: 57 if unit.strip() == "": 58 continue 59 var index = lowered.find(unit.lower()) 60 if index >= 0: 61 var number_start = _backward_number_start(text, index) 62 if number_start >= 0: 63 candidates.append( 64 Candidate( 65 kind="quantity", 66 text=String( 67 text[ 68 byte = number_start : index + unit.byte_length() 69 ] 70 ), 71 start=number_start, 72 end=index + unit.byte_length(), 73 ) 74 ) 75 76 for date_word in known_dates: 77 if date_word.strip() == "": 78 continue 79 var index = lowered.find(date_word.lower()) 80 if index >= 0: 81 candidates.append( 82 Candidate( 83 kind="date", 84 text=String(date_word), 85 start=index, 86 end=index + date_word.byte_length(), 87 ) 88 ) 89 return candidates^ 90 91 92 def candidate_kinds(candidates: List[Candidate]) -> List[String]: 93 var kinds = List[String]() 94 for candidate in candidates: 95 var seen = False 96 for kind in kinds: 97 if kind == candidate.kind: 98 seen = True 99 if not seen: 100 kinds.append(String(candidate.kind)) 101 return kinds^