15815213711
2024-08-26 67b8b6731811983447e053d4396b3708c14dfe3c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { VALID_DIGITS } from '../../constants.js'
 
// The RFC 3966 format for extensions.
const RFC3966_EXTN_PREFIX = ';ext='
 
/**
 * Helper method for constructing regular expressions for parsing. Creates
 * an expression that captures up to max_length digits.
 * @return {string} RegEx pattern to capture extension digits.
 */
const getExtensionDigitsPattern = (maxLength) => `([${VALID_DIGITS}]{1,${maxLength}})`
 
/**
 * Helper initialiser method to create the regular-expression pattern to match
 * extensions.
 * Copy-pasted from Google's `libphonenumber`:
 * https://github.com/google/libphonenumber/blob/55b2646ec9393f4d3d6661b9c82ef9e258e8b829/javascript/i18n/phonenumbers/phonenumberutil.js#L759-L766
 * @return {string} RegEx pattern to capture extensions.
 */
export default function createExtensionPattern(purpose) {
    // We cap the maximum length of an extension based on the ambiguity of the way
    // the extension is prefixed. As per ITU, the officially allowed length for
    // extensions is actually 40, but we don't support this since we haven't seen real
    // examples and this introduces many false interpretations as the extension labels
    // are not standardized.
    /** @type {string} */
    var extLimitAfterExplicitLabel = '20';
    /** @type {string} */
    var extLimitAfterLikelyLabel = '15';
    /** @type {string} */
    var extLimitAfterAmbiguousChar = '9';
    /** @type {string} */
    var extLimitWhenNotSure = '6';
 
    /** @type {string} */
    var possibleSeparatorsBetweenNumberAndExtLabel = "[ \u00A0\\t,]*";
    // Optional full stop (.) or colon, followed by zero or more spaces/tabs/commas.
    /** @type {string} */
    var possibleCharsAfterExtLabel = "[:\\.\uFF0E]?[ \u00A0\\t,-]*";
    /** @type {string} */
    var optionalExtnSuffix = "#?";
 
    // Here the extension is called out in more explicit way, i.e mentioning it obvious
    // patterns like "ext.".
    /** @type {string} */
    var explicitExtLabels =
      "(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|\u0434\u043E\u0431|anexo)";
    // One-character symbols that can be used to indicate an extension, and less
    // commonly used or more ambiguous extension labels.
    /** @type {string} */
    var ambiguousExtLabels = "(?:[x\uFF58#\uFF03~\uFF5E]|int|\uFF49\uFF4E\uFF54)";
    // When extension is not separated clearly.
    /** @type {string} */
    var ambiguousSeparator = "[- ]+";
    // This is the same as possibleSeparatorsBetweenNumberAndExtLabel, but not matching
    // comma as extension label may have it.
    /** @type {string} */
    var possibleSeparatorsNumberExtLabelNoComma = "[ \u00A0\\t]*";
    // ",," is commonly used for auto dialling the extension when connected. First
    // comma is matched through possibleSeparatorsBetweenNumberAndExtLabel, so we do
    // not repeat it here. Semi-colon works in Iphone and Android also to pop up a
    // button with the extension number following.
    /** @type {string} */
    var autoDiallingAndExtLabelsFound = "(?:,{2}|;)";
 
    /** @type {string} */
    var rfcExtn = RFC3966_EXTN_PREFIX
         + getExtensionDigitsPattern(extLimitAfterExplicitLabel);
    /** @type {string} */
    var explicitExtn = possibleSeparatorsBetweenNumberAndExtLabel + explicitExtLabels
         + possibleCharsAfterExtLabel
         + getExtensionDigitsPattern(extLimitAfterExplicitLabel)
         + optionalExtnSuffix;
    /** @type {string} */
    var ambiguousExtn = possibleSeparatorsBetweenNumberAndExtLabel + ambiguousExtLabels
         + possibleCharsAfterExtLabel
    + getExtensionDigitsPattern(extLimitAfterAmbiguousChar)
    + optionalExtnSuffix;
    /** @type {string} */
    var americanStyleExtnWithSuffix = ambiguousSeparator
    + getExtensionDigitsPattern(extLimitWhenNotSure) + "#";
 
    /** @type {string} */
    var autoDiallingExtn = possibleSeparatorsNumberExtLabelNoComma
         + autoDiallingAndExtLabelsFound + possibleCharsAfterExtLabel
         + getExtensionDigitsPattern(extLimitAfterLikelyLabel)
    + optionalExtnSuffix;
    /** @type {string} */
    var onlyCommasExtn = possibleSeparatorsNumberExtLabelNoComma
        + "(?:,)+" + possibleCharsAfterExtLabel
        + getExtensionDigitsPattern(extLimitAfterAmbiguousChar)
        + optionalExtnSuffix;
 
    // The first regular expression covers RFC 3966 format, where the extension is added
    // using ";ext=". The second more generic where extension is mentioned with explicit
    // labels like "ext:". In both the above cases we allow more numbers in extension than
    // any other extension labels. The third one captures when single character extension
    // labels or less commonly used labels are used. In such cases we capture fewer
    // extension digits in order to reduce the chance of falsely interpreting two
    // numbers beside each other as a number + extension. The fourth one covers the
    // special case of American numbers where the extension is written with a hash
    // at the end, such as "- 503#". The fifth one is exclusively for extension
    // autodialling formats which are used when dialling and in this case we accept longer
    // extensions. The last one is more liberal on the number of commas that acts as
    // extension labels, so we have a strict cap on the number of digits in such extensions.
    return rfcExtn + "|"
           + explicitExtn + "|"
           + ambiguousExtn + "|"
           + americanStyleExtnWithSuffix + "|"
           + autoDiallingExtn + "|"
           + onlyCommasExtn;
}