Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions csharp/PhoneNumbers/PhoneNumberUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2536,7 +2536,7 @@
internal bool MaybeStripNationalPrefixAndCarrierCode(StringBuilder number, string numberString, PhoneMetadata metadata, bool getCarrier, out string carrierCode)
{
carrierCode = null;
var numberLength = numberString?.Length ?? number.Length;

Check warning

Code scanning / CodeQL

Dereferenced variable may be null Warning

Variable
number
may be null at this access as suggested by
this
null check.
Variable
number
may be null at this access as suggested by
this
null check.
Variable
number
may be null at this access as suggested by
this
null check.
if (numberLength == 0 || !metadata.HasNationalPrefixForParsing)
{
// Early return for numbers of zero length.
Expand All @@ -2544,6 +2544,25 @@
}
// Attempt to parse the first digits as a national prefix.
numberString ??= number.ToString();

// Whether the groups are needed at all is known before matching: only a transform rule or
// a requested carrier code reads them. Without either, the length of the prefix is the
// only thing this method uses, and that can be had without materialising a Match.
if (string.IsNullOrEmpty(metadata.NationalPrefixTransformRule) && !getCarrier)
{
var prefixLength = metadata.MatchNationalPrefixLengthForParsing(numberString);
if (prefixLength < 0)
return false;

var rule = metadata.GeneralDesc.GetNationalNumberPattern();
// If the original number was viable, and the resultant number is not, we return.
if (rule.IsMatchAll(numberString) && !IsMatchAllFrom(rule, numberString, prefixLength))
return false;

number?.Remove(0, prefixLength);
return true;
}

var prefixMatch = metadata.MatchNationalPrefixForParsing(numberString);
if (prefixMatch?.Success == true)
{
Expand Down
13 changes: 13 additions & 0 deletions csharp/PhoneNumbers/PhoneRegex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ public PhoneRegex(string pattern, RegexOptions options)
public Match MatchAll(string value) => allRegex.Value.Match(value);

public bool IsMatchBeginning(string value) => beginRegex.Value.IsMatch(value);

#if NET7_0_OR_GREATER
/// <summary>
/// Length of the match anchored at the start, or -1 if there is none. EnumerateMatches yields
/// a ValueMatch struct, so a caller that only needs the length never materialises a Match.
/// </summary>
internal int MatchBeginningLength(ReadOnlySpan<char> value)
{
foreach (var match in beginRegex.Value.EnumerateMatches(value))
return match.Length;
return -1;
}
#endif
public Match MatchBeginning(string value) => beginRegex.Value.Match(value);
}
}
24 changes: 24 additions & 0 deletions csharp/PhoneNumbers/Phonemetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,30 @@ internal Match MatchNationalPrefixForParsing(string value)
return PhoneRegex.Get(NationalPrefixForParsing).MatchBeginning(value);
}

/// <summary>
/// How many characters of the national prefix <paramref name="value"/> starts with, or -1 if
/// it does not start with one. Callers that only need to know how much to strip use this so
/// no Match is materialised; the groups are only needed for a transform rule or carrier code.
/// </summary>
internal int MatchNationalPrefixLengthForParsing(string value)
{
if (_nationalPrefixForParsingLiteral == 0)
_nationalPrefixForParsingLiteral = (sbyte)(Regex.Escape(NationalPrefixForParsing) == NationalPrefixForParsing ? 1 : -1);

// A literal prefix matches itself, so its length is known without running the regex.
if (_nationalPrefixForParsingLiteral > 0)
return value.StartsWith(NationalPrefixForParsing, StringComparison.Ordinal)
? NationalPrefixForParsing.Length
: -1;

#if NET7_0_OR_GREATER
return PhoneRegex.Get(NationalPrefixForParsing).MatchBeginningLength(value.AsSpan());
#else
var match = PhoneRegex.Get(NationalPrefixForParsing).MatchBeginning(value);
return match.Success ? match.Length : -1;
#endif
}

public bool HasNationalPrefixTransformRule => NationalPrefixTransformRule?.Length > 0;
public string NationalPrefixTransformRule { get; internal set; } = "";

Expand Down