// Allow implicit conversion from char16_t* to UnicodeString for this file: // Helpful in toString methods and elsewhere. #define UNISTR_FROM_STRING_EXPLICIT
// ICU-TC meeting, April 11, 2018: accept percent/permille only if it is in the pattern, // and to maintain regressive behavior, divide by 100 even if no percent sign is present. if (!isStrict && affixProvider.get().containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) {
parser->addMatcher(parser->fLocalMatchers.percent = {symbols});
} if (!isStrict && affixProvider.get().containsSymbolType(AffixPatternType::TYPE_PERMILLE, status)) {
parser->addMatcher(parser->fLocalMatchers.permille = {symbols});
}
/////////////////////////////// /// OTHER STANDARD MATCHERS /// ///////////////////////////////
if (!isStrict) {
parser->addMatcher(parser->fLocalMatchers.plusSign = {symbols, false});
parser->addMatcher(parser->fLocalMatchers.minusSign = {symbols, false});
}
parser->addMatcher(parser->fLocalMatchers.nan = {symbols});
parser->addMatcher(parser->fLocalMatchers.infinity = {symbols});
UnicodeString padString = properties.padString; if (!padString.isBogus() && !ignorables.getSet()->contains(padString)) {
parser->addMatcher(parser->fLocalMatchers.padding = {padString});
}
parser->addMatcher(parser->fLocalMatchers.ignorables);
parser->addMatcher(parser->fLocalMatchers.decimal = {symbols, grouper, parseFlags}); // NOTE: parseNoExponent doesn't disable scientific parsing if we have a scientific formatter if (!properties.parseNoExponent || properties.minimumExponentDigits > 0) {
parser->addMatcher(parser->fLocalMatchers.scientific = {symbols, grouper});
}
void NumberParserImpl::parse(const UnicodeString& input, int32_t start, bool greedy, ParsedNumber& result,
UErrorCode& status) const { if (U_FAILURE(status)) { return;
}
U_ASSERT(fFrozen); // TODO: Check start >= 0 and start < input.length()
StringSegment segment(input, 0 != (fParseFlags & PARSE_FLAG_IGNORE_CASE));
segment.adjustOffset(start); if (greedy) {
parseGreedy(segment, result, status);
} elseif (0 != (fParseFlags & PARSE_FLAG_ALLOW_INFINITE_RECURSION)) { // Start at 1 so that recursionLevels never gets to 0
parseLongestRecursive(segment, result, 1, status);
} else { // Arbitrary recursion safety limit: 100 levels.
parseLongestRecursive(segment, result, -100, status);
} for (int32_t i = 0; i < fNumMatchers; i++) {
fMatchers[i]->postProcess(result);
}
result.postProcess();
}
void NumberParserImpl::parseGreedy(StringSegment& segment, ParsedNumber& result,
UErrorCode& status) const { // Note: this method is not recursive in order to avoid stack overflow. for (int i = 0; i <fNumMatchers;) { // Base Case if (segment.length() == 0) { return;
} const NumberParseMatcher* matcher = fMatchers[i]; if (!matcher->smokeTest(segment)) { // Matcher failed smoke test: try the next one
i++; continue;
}
int32_t initialOffset = segment.getOffset();
matcher->match(segment, result, status); if (U_FAILURE(status)) { return;
} if (segment.getOffset() != initialOffset) { // Greedy heuristic: accept the match and loop back
i = 0; continue;
} else { // Matcher did not match: try the next one
i++; continue;
}
UPRV_UNREACHABLE_EXIT;
}
// NOTE: If we get here, the greedy parse completed without consuming the entire string.
}
void NumberParserImpl::parseLongestRecursive(StringSegment& segment, ParsedNumber& result,
int32_t recursionLevels,
UErrorCode& status) const { // Base Case if (segment.length() == 0) { return;
}
// Safety against stack overflow if (recursionLevels == 0) { return;
}
// TODO: Give a nice way for the matcher to reset the ParsedNumber?
ParsedNumber initial(result);
ParsedNumber candidate;
int initialOffset = segment.getOffset(); for (int32_t i = 0; i < fNumMatchers; i++) { const NumberParseMatcher* matcher = fMatchers[i]; if (!matcher->smokeTest(segment)) { continue;
}
// In a non-greedy parse, we attempt all possible matches and pick the best. for (int32_t charsToConsume = 0; charsToConsume < segment.length();) {
charsToConsume += U16_LENGTH(segment.codePointAt(charsToConsume));
// Run the matcher on a segment of the current length.
candidate = initial;
segment.setLength(charsToConsume); bool maybeMore = matcher->match(segment, candidate, status);
segment.resetLength(); if (U_FAILURE(status)) { return;
}
// If the entire segment was consumed, recurse. if (segment.getOffset() - initialOffset == charsToConsume) {
parseLongestRecursive(segment, candidate, recursionLevels + 1, status); if (U_FAILURE(status)) { return;
} if (candidate.isBetterThan(result)) {
result = candidate;
}
}
// Since the segment can be re-used, reset the offset. // This does not have an effect if the matcher did not consume any chars.
segment.setOffset(initialOffset);
// Unless the matcher wants to see the next char, continue to the next matcher. if (!maybeMore) { break;
}
}
}
}
UnicodeString NumberParserImpl::toString() const {
UnicodeString result(u"); for (int32_t i = 0; i < fNumMatchers; i++) {
result.append(u' ');
result.append(fMatchers[i]->toString());
}
result.append(u" ]>", -1); return result;
}
#endif/* #if !UCONFIG_NO_FORMATTING */
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.