1 /* melder_search.cpp
2 *
3 * Copyright (C) 1992-2018,2020 Paul Boersma
4 *
5 * This code is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This code is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this work. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "melder.h"
20
21 /********** NUMBER AND STRING COMPARISONS **********/
22
Melder_numberMatchesCriterion(double value,kMelder_number which,double criterion)23 bool Melder_numberMatchesCriterion (double value, kMelder_number which, double criterion) {
24 return
25 (which == kMelder_number::EQUAL_TO && value == criterion) ||
26 (which == kMelder_number::NOT_EQUAL_TO && value != criterion) ||
27 (which == kMelder_number::LESS_THAN && value < criterion) ||
28 (which == kMelder_number::LESS_THAN_OR_EQUAL_TO && value <= criterion) ||
29 (which == kMelder_number::GREATER_THAN && value > criterion) ||
30 (which == kMelder_number::GREATER_THAN_OR_EQUAL_TO && value >= criterion);
31 }
32
str32str_word_optionallyCaseSensitive(conststring32 string,conststring32 find,bool ink,bool caseSensitive,bool startFree,bool endFree)33 inline static char32 * str32str_word_optionallyCaseSensitive (conststring32 string, conststring32 find,
34 bool ink, bool caseSensitive, bool startFree, bool endFree) noexcept
35 {
36 integer length = str32len (find);
37 if (length == 0)
38 return (char32 *) string;
39 conststring32 movingString = string;
40 do {
41 conststring32 movingFind = find;
42 char32 firstCharacter = ( caseSensitive ? * movingFind ++ : Melder_toLowerCase (* movingFind ++) ); // optimization
43 do {
44 char32 kar;
45 do {
46 kar = ( caseSensitive ? * movingString ++ : Melder_toLowerCase (* movingString ++) );
47 if (kar == U'\0') return nullptr;
48 } while (kar != firstCharacter);
49 } while (caseSensitive ? str32ncmp (movingString, movingFind, length - 1) : str32ncmp_caseInsensitive (movingString, movingFind, length - 1));
50 /*
51 We found a match.
52 */
53 movingString --;
54 if ((startFree || movingString == string || ( ink ? Melder_isHorizontalOrVerticalSpace (movingString [-1]) : ! Melder_isWordCharacter (movingString [-1]) )) &&
55 (endFree || movingString [length] == U'\0' || (ink ? Melder_isHorizontalOrVerticalSpace (movingString [length]) : ! Melder_isWordCharacter (movingString [length]) )))
56 {
57 return (char32 *) movingString;
58 } else {
59 movingString ++;
60 }
61 } while (true);
62 return nullptr; // can never occur
63 }
64
Melder_stringMatchesCriterion(conststring32 value,kMelder_string which,conststring32 criterion,bool caseSensitive)65 bool Melder_stringMatchesCriterion (conststring32 value, kMelder_string which, conststring32 criterion, bool caseSensitive) {
66 if (! value)
67 value = U""; // regard null strings as empty strings, as is usual in Praat
68 if (! criterion)
69 criterion = U""; // regard null strings as empty strings, as is usual in Praat
70 switch (which)
71 {
72 case kMelder_string::UNDEFINED:
73 {
74 Melder_fatal (U"Melder_stringMatchesCriterion: unknown criterion.");
75 }
76 case kMelder_string::EQUAL_TO:
77 case kMelder_string::NOT_EQUAL_TO:
78 {
79 bool doesMatch = str32equ_optionallyCaseSensitive (value, criterion, caseSensitive);
80 return which == kMelder_string::EQUAL_TO ? doesMatch : ! doesMatch;
81 }
82 case kMelder_string::CONTAINS:
83 case kMelder_string::DOES_NOT_CONTAIN:
84 {
85 bool doesMatch = !! str32str_optionallyCaseSensitive (value, criterion, caseSensitive);
86 return which == kMelder_string::CONTAINS ? doesMatch : ! doesMatch;
87 }
88 case kMelder_string::STARTS_WITH:
89 case kMelder_string::DOES_NOT_START_WITH:
90 {
91 bool doesMatch = str32nequ_optionallyCaseSensitive (value, criterion, str32len (criterion), caseSensitive);
92 return which == kMelder_string::STARTS_WITH ? doesMatch : ! doesMatch;
93 }
94 case kMelder_string::ENDS_WITH:
95 case kMelder_string::DOES_NOT_END_WITH:
96 {
97 integer criterionLength = str32len (criterion), valueLength = str32len (value);
98 bool doesMatch = criterionLength <= valueLength &&
99 str32equ_optionallyCaseSensitive (value + valueLength - criterionLength, criterion, caseSensitive);
100 return which == kMelder_string::ENDS_WITH ? doesMatch : ! doesMatch;
101 }
102 case kMelder_string::CONTAINS_WORD:
103 case kMelder_string::DOES_NOT_CONTAIN_WORD:
104 {
105 bool doesMatch = !! str32str_word_optionallyCaseSensitive (value, criterion, false, caseSensitive, false, false);
106 return which == kMelder_string::CONTAINS_WORD ? doesMatch : ! doesMatch;
107 }
108 case kMelder_string::CONTAINS_WORD_STARTING_WITH:
109 case kMelder_string::DOES_NOT_CONTAIN_WORD_STARTING_WITH:
110 {
111 bool doesMatch = !! str32str_word_optionallyCaseSensitive (value, criterion, false, caseSensitive, false, true);
112 return which == kMelder_string::CONTAINS_WORD_STARTING_WITH ? doesMatch : ! doesMatch;
113 }
114 case kMelder_string::CONTAINS_WORD_ENDING_WITH:
115 case kMelder_string::DOES_NOT_CONTAIN_WORD_ENDING_WITH:
116 {
117 bool doesMatch = !! str32str_word_optionallyCaseSensitive (value, criterion, false, caseSensitive, true, false);
118 return which == kMelder_string::CONTAINS_WORD_ENDING_WITH ? doesMatch : ! doesMatch;
119 }
120 case kMelder_string::CONTAINS_INK:
121 case kMelder_string::DOES_NOT_CONTAIN_INK:
122 {
123 bool doesMatch = !! str32str_word_optionallyCaseSensitive (value, criterion, true, caseSensitive, false, false);
124 return which == kMelder_string::CONTAINS_INK ? doesMatch : ! doesMatch;
125 }
126 case kMelder_string::CONTAINS_INK_STARTING_WITH:
127 case kMelder_string::DOES_NOT_CONTAIN_INK_STARTING_WITH:
128 {
129 bool doesMatch = !! str32str_word_optionallyCaseSensitive (value, criterion, true, caseSensitive, false, true);
130 return which == kMelder_string::CONTAINS_INK_STARTING_WITH ? doesMatch : ! doesMatch;
131 }
132 case kMelder_string::CONTAINS_INK_ENDING_WITH:
133 case kMelder_string::DOES_NOT_CONTAIN_INK_ENDING_WITH:
134 {
135 bool doesMatch = !! str32str_word_optionallyCaseSensitive (value, criterion, true, caseSensitive, true, false);
136 return which == kMelder_string::CONTAINS_INK_ENDING_WITH ? doesMatch : ! doesMatch;
137 }
138 case kMelder_string::MATCH_REGEXP:
139 {
140 char32 *place = nullptr;
141 regexp *compiled_regexp = CompileRE_throwable (criterion, ! REDFLT_CASE_INSENSITIVE);
142 if (ExecRE (compiled_regexp, nullptr, value, nullptr, 0, U'\0', U'\0', nullptr, nullptr))
143 place = compiled_regexp -> startp [0];
144 free (compiled_regexp);
145 return !! place;
146 }
147 }
148 return false; // should not occur
149 }
150
151 /* End of file melder_search.cpp */
152