swaggest/php-json-schema

View on GitHub
src/Constraint/Format/Iri.php

Summary

Maintainability
F
4 days
Test Coverage
<?php

namespace Swaggest\JsonSchema\Constraint\Format;

class Iri
{

    /**
     * @param string $data
     * @param int $options
     * @return null|string
     */
    public static function validationError($data, $options = Uri::IS_SCHEME_REQUIRED)
    {
        $error = Iri::unicodeValidationError($data, $sanitized);
        if ($error !== null) {
            return $error;
        }

        return Uri::validationError($sanitized, $options);
    }


    /**
     * @see http://www.unicode.org/faq/idn.html
     * @see https://gist.github.com/rxu/0660eef7a2f9e7992db6
     * @param string $data
     * @param string $sanitized
     * @return null|string
     */
    public static function unicodeValidationError($data, &$sanitized = null)
    {
        static $excluded = array(
            "\xD9\x80" => '\u0640',
            "\xDF\xBA" => '\u07FA',
            "\xE3\x80\xAE" => '\u302E',
            "\xE3\x80\xAF" => '\u302F',
            "\xE3\x80\xB1" => '\u3031',
            "\xE3\x80\xB2" => '\u3032',
            "\xE3\x80\xB3" => '\u3033',
            "\xE3\x80\xB4" => '\u3034',
            "\xE3\x80\xB5" => '\u3035',
            "\xE3\x80\xBB" => '\u303B',

            // Remove characters used for archaic Hangul (Korean) - \p{HST=L} and \p{HST=V}
            // as per http://unicode.org/Public/UNIDATA/HangulSyllableType.txt
            "\xE1\x84\x80" => '\u1100',
            "\xE1\x84\x81" => '\u1101',
            "\xE1\x84\x82" => '\u1102',
            "\xE1\x84\x83" => '\u1103',
            "\xE1\x84\x84" => '\u1104',
            "\xE1\x84\x85" => '\u1105',
            "\xE1\x84\x86" => '\u1106',
            "\xE1\x84\x87" => '\u1107',
            "\xE1\x84\x88" => '\u1108',
            "\xE1\x84\x89" => '\u1109',
            "\xE1\x84\x8A" => '\u110a',
            "\xE1\x84\x8B" => '\u110b',
            "\xE1\x84\x8C" => '\u110c',
            "\xE1\x84\x8D" => '\u110d',
            "\xE1\x84\x8E" => '\u110e',
            "\xE1\x84\x8F" => '\u110f',
            "\xE1\x84\x90" => '\u1110',
            "\xE1\x84\x91" => '\u1111',
            "\xE1\x84\x92" => '\u1112',
            "\xE1\x84\x93" => '\u1113',
            "\xE1\x84\x94" => '\u1114',
            "\xE1\x84\x95" => '\u1115',
            "\xE1\x84\x96" => '\u1116',
            "\xE1\x84\x97" => '\u1117',
            "\xE1\x84\x98" => '\u1118',
            "\xE1\x84\x99" => '\u1119',
            "\xE1\x84\x9A" => '\u111a',
            "\xE1\x84\x9B" => '\u111b',
            "\xE1\x84\x9C" => '\u111c',
            "\xE1\x84\x9D" => '\u111d',
            "\xE1\x84\x9E" => '\u111e',
            "\xE1\x84\x9F" => '\u111f',
            "\xE1\x84\xA0" => '\u1120',
            "\xE1\x84\xA1" => '\u1121',
            "\xE1\x84\xA2" => '\u1122',
            "\xE1\x84\xA3" => '\u1123',
            "\xE1\x84\xA4" => '\u1124',
            "\xE1\x84\xA5" => '\u1125',
            "\xE1\x84\xA6" => '\u1126',
            "\xE1\x84\xA7" => '\u1127',
            "\xE1\x84\xA8" => '\u1128',
            "\xE1\x84\xA9" => '\u1129',
            "\xE1\x84\xAA" => '\u112a',
            "\xE1\x84\xAB" => '\u112b',
            "\xE1\x84\xAC" => '\u112c',
            "\xE1\x84\xAD" => '\u112d',
            "\xE1\x84\xAE" => '\u112e',
            "\xE1\x84\xAF" => '\u112f',
            "\xE1\x84\xB0" => '\u1130',
            "\xE1\x84\xB1" => '\u1131',
            "\xE1\x84\xB2" => '\u1132',
            "\xE1\x84\xB3" => '\u1133',
            "\xE1\x84\xB4" => '\u1134',
            "\xE1\x84\xB5" => '\u1135',
            "\xE1\x84\xB6" => '\u1136',
            "\xE1\x84\xB7" => '\u1137',
            "\xE1\x84\xB8" => '\u1138',
            "\xE1\x84\xB9" => '\u1139',
            "\xE1\x84\xBA" => '\u113a',
            "\xE1\x84\xBB" => '\u113b',
            "\xE1\x84\xBC" => '\u113c',
            "\xE1\x84\xBD" => '\u113d',
            "\xE1\x84\xBE" => '\u113e',
            "\xE1\x84\xBF" => '\u113f',
            "\xE1\x85\x80" => '\u1140',
            "\xE1\x85\x81" => '\u1141',
            "\xE1\x85\x82" => '\u1142',
            "\xE1\x85\x83" => '\u1143',
            "\xE1\x85\x84" => '\u1144',
            "\xE1\x85\x85" => '\u1145',
            "\xE1\x85\x86" => '\u1146',
            "\xE1\x85\x87" => '\u1147',
            "\xE1\x85\x88" => '\u1148',
            "\xE1\x85\x89" => '\u1149',
            "\xE1\x85\x8A" => '\u114a',
            "\xE1\x85\x8B" => '\u114b',
            "\xE1\x85\x8C" => '\u114c',
            "\xE1\x85\x8D" => '\u114d',
            "\xE1\x85\x8E" => '\u114e',
            "\xE1\x85\x8F" => '\u114f',
            "\xE1\x85\x90" => '\u1150',
            "\xE1\x85\x91" => '\u1151',
            "\xE1\x85\x92" => '\u1152',
            "\xE1\x85\x93" => '\u1153',
            "\xE1\x85\x94" => '\u1154',
            "\xE1\x85\x95" => '\u1155',
            "\xE1\x85\x96" => '\u1156',
            "\xE1\x85\x97" => '\u1157',
            "\xE1\x85\x98" => '\u1158',
            "\xE1\x85\x99" => '\u1159',
            "\xE1\x85\x9A" => '\u115a',
            "\xE1\x85\x9B" => '\u115b',
            "\xE1\x85\x9C" => '\u115c',
            "\xE1\x85\x9D" => '\u115d',
            "\xE1\x85\x9E" => '\u115e',
            "\xE1\x85\x9F" => '\u115f',
            "\xEA\xA5\xA0" => '\ua960',
            "\xEA\xA5\xA1" => '\ua961',
            "\xEA\xA5\xA2" => '\ua962',
            "\xEA\xA5\xA3" => '\ua963',
            "\xEA\xA5\xA4" => '\ua964',
            "\xEA\xA5\xA5" => '\ua965',
            "\xEA\xA5\xA6" => '\ua966',
            "\xEA\xA5\xA7" => '\ua967',
            "\xEA\xA5\xA8" => '\ua968',
            "\xEA\xA5\xA9" => '\ua969',
            "\xEA\xA5\xAA" => '\ua96a',
            "\xEA\xA5\xAB" => '\ua96b',
            "\xEA\xA5\xAC" => '\ua96c',
            "\xEA\xA5\xAD" => '\ua96d',
            "\xEA\xA5\xAE" => '\ua96e',
            "\xEA\xA5\xAF" => '\ua96f',
            "\xEA\xA5\xB0" => '\ua970',
            "\xEA\xA5\xB1" => '\ua971',
            "\xEA\xA5\xB2" => '\ua972',
            "\xEA\xA5\xB3" => '\ua973',
            "\xEA\xA5\xB4" => '\ua974',
            "\xEA\xA5\xB5" => '\ua975',
            "\xEA\xA5\xB6" => '\ua976',
            "\xEA\xA5\xB7" => '\ua977',
            "\xEA\xA5\xB8" => '\ua978',
            "\xEA\xA5\xB9" => '\ua979',
            "\xEA\xA5\xBA" => '\ua97a',
            "\xEA\xA5\xBB" => '\ua97b',
            "\xEA\xA5\xBC" => '\ua97c',
            "\xE1\x85\xA0" => '\u1160',
            "\xE1\x85\xA1" => '\u1161',
            "\xE1\x85\xA2" => '\u1162',
            "\xE1\x85\xA3" => '\u1163',
            "\xE1\x85\xA4" => '\u1164',
            "\xE1\x85\xA5" => '\u1165',
            "\xE1\x85\xA6" => '\u1166',
            "\xE1\x85\xA7" => '\u1167',
            "\xE1\x85\xA8" => '\u1168',
            "\xE1\x85\xA9" => '\u1169',
            "\xE1\x85\xAA" => '\u116a',
            "\xE1\x85\xAB" => '\u116b',
            "\xE1\x85\xAC" => '\u116c',
            "\xE1\x85\xAD" => '\u116d',
            "\xE1\x85\xAE" => '\u116e',
            "\xE1\x85\xAF" => '\u116f',
            "\xE1\x85\xB0" => '\u1170',
            "\xE1\x85\xB1" => '\u1171',
            "\xE1\x85\xB2" => '\u1172',
            "\xE1\x85\xB3" => '\u1173',
            "\xE1\x85\xB4" => '\u1174',
            "\xE1\x85\xB5" => '\u1175',
            "\xE1\x85\xB6" => '\u1176',
            "\xE1\x85\xB7" => '\u1177',
            "\xE1\x85\xB8" => '\u1178',
            "\xE1\x85\xB9" => '\u1179',
            "\xE1\x85\xBA" => '\u117a',
            "\xE1\x85\xBB" => '\u117b',
            "\xE1\x85\xBC" => '\u117c',
            "\xE1\x85\xBD" => '\u117d',
            "\xE1\x85\xBE" => '\u117e',
            "\xE1\x85\xBF" => '\u117f',
            "\xE1\x86\x80" => '\u1180',
            "\xE1\x86\x81" => '\u1181',
            "\xE1\x86\x82" => '\u1182',
            "\xE1\x86\x83" => '\u1183',
            "\xE1\x86\x84" => '\u1184',
            "\xE1\x86\x85" => '\u1185',
            "\xE1\x86\x86" => '\u1186',
            "\xE1\x86\x87" => '\u1187',
            "\xE1\x86\x88" => '\u1188',
            "\xE1\x86\x89" => '\u1189',
            "\xE1\x86\x8A" => '\u118a',
            "\xE1\x86\x8B" => '\u118b',
            "\xE1\x86\x8C" => '\u118c',
            "\xE1\x86\x8D" => '\u118d',
            "\xE1\x86\x8E" => '\u118e',
            "\xE1\x86\x8F" => '\u118f',
            "\xE1\x86\x90" => '\u1190',
            "\xE1\x86\x91" => '\u1191',
            "\xE1\x86\x92" => '\u1192',
            "\xE1\x86\x93" => '\u1193',
            "\xE1\x86\x94" => '\u1194',
            "\xE1\x86\x95" => '\u1195',
            "\xE1\x86\x96" => '\u1196',
            "\xE1\x86\x97" => '\u1197',
            "\xE1\x86\x98" => '\u1198',
            "\xE1\x86\x99" => '\u1199',
            "\xE1\x86\x9A" => '\u119a',
            "\xE1\x86\x9B" => '\u119b',
            "\xE1\x86\x9C" => '\u119c',
            "\xE1\x86\x9D" => '\u119d',
            "\xE1\x86\x9E" => '\u119e',
            "\xE1\x86\x9F" => '\u119f',
            "\xE1\x86\xA0" => '\u11a0',
            "\xE1\x86\xA1" => '\u11a1',
            "\xE1\x86\xA2" => '\u11a2',
            "\xE1\x86\xA3" => '\u11a3',
            "\xE1\x86\xA4" => '\u11a4',
            "\xE1\x86\xA5" => '\u11a5',
            "\xE1\x86\xA6" => '\u11a6',
            "\xE1\x86\xA7" => '\u11a7',
            "\xED\x9E\xB0" => '\ud7b0',
            "\xED\x9E\xB1" => '\ud7b1',
            "\xED\x9E\xB2" => '\ud7b2',
            "\xED\x9E\xB3" => '\ud7b3',
            "\xED\x9E\xB4" => '\ud7b4',
            "\xED\x9E\xB5" => '\ud7b5',
            "\xED\x9E\xB6" => '\ud7b6',
            "\xED\x9E\xB7" => '\ud7b7',
            "\xED\x9E\xB8" => '\ud7b8',
            "\xED\x9E\xB9" => '\ud7b9',
            "\xED\x9E\xBA" => '\ud7ba',
            "\xED\x9E\xBB" => '\ud7bb',
            "\xED\x9E\xBC" => '\ud7bc',
            "\xED\x9E\xBD" => '\ud7bd',
            "\xED\x9E\xBE" => '\ud7be',
            "\xED\x9E\xBF" => '\ud7bf',
            "\xED\x9F\x80" => '\ud7c0',
            "\xED\x9F\x81" => '\ud7c1',
            "\xED\x9F\x82" => '\ud7c2',
            "\xED\x9F\x83" => '\ud7c3',
            "\xED\x9F\x84" => '\ud7c4',
            "\xED\x9F\x85" => '\ud7c5',
            "\xED\x9F\x86" => '\ud7c6',

            // Remove three blocks of technical or archaic symbols.
            // \p{block=Combining_Diacritical_Marks_For_Symbols}
            "\xE2\x83\x90" => '\u20d0',
            "\xE2\x83\x91" => '\u20d1',
            "\xE2\x83\x92" => '\u20d2',
            "\xE2\x83\x93" => '\u20d3',
            "\xE2\x83\x94" => '\u20d4',
            "\xE2\x83\x95" => '\u20d5',
            "\xE2\x83\x96" => '\u20d6',
            "\xE2\x83\x97" => '\u20d7',
            "\xE2\x83\x98" => '\u20d8',
            "\xE2\x83\x99" => '\u20d9',
            "\xE2\x83\x9A" => '\u20da',
            "\xE2\x83\x9B" => '\u20db',
            "\xE2\x83\x9C" => '\u20dc',
            "\xE2\x83\x9D" => '\u20dd',
            "\xE2\x83\x9E" => '\u20de',
            "\xE2\x83\x9F" => '\u20df',
            "\xE2\x83\xA0" => '\u20e0',
            "\xE2\x83\xA1" => '\u20e1',
            "\xE2\x83\xA2" => '\u20e2',
            "\xE2\x83\xA3" => '\u20e3',
            "\xE2\x83\xA4" => '\u20e4',
            "\xE2\x83\xA5" => '\u20e5',
            "\xE2\x83\xA6" => '\u20e6',
            "\xE2\x83\xA7" => '\u20e7',
            "\xE2\x83\xA8" => '\u20e8',
            "\xE2\x83\xA9" => '\u20e9',
            "\xE2\x83\xAA" => '\u20ea',
            "\xE2\x83\xAB" => '\u20eb',
            "\xE2\x83\xAC" => '\u20ec',
            "\xE2\x83\xAD" => '\u20ed',
            "\xE2\x83\xAE" => '\u20ee',
            "\xE2\x83\xAF" => '\u20ef',
            "\xE2\x83\xB0" => '\u20f0',
            "\xE2\x83\xB1" => '\u20f1',
            "\xE2\x83\xB2" => '\u20f2',
            "\xE2\x83\xB3" => '\u20f3',
            "\xE2\x83\xB4" => '\u20f4',
            "\xE2\x83\xB5" => '\u20f5',
            "\xE2\x83\xB6" => '\u20f6',
            "\xE2\x83\xB7" => '\u20f7',
            "\xE2\x83\xB8" => '\u20f8',
            "\xE2\x83\xB9" => '\u20f9',
            "\xE2\x83\xBA" => '\u20fa',
            "\xE2\x83\xBB" => '\u20fb',
            "\xE2\x83\xBC" => '\u20fc',
            "\xE2\x83\xBD" => '\u20fd',
            "\xE2\x83\xBE" => '\u20fe',
            "\xE2\x83\xBF" => '\u20ff',

            // \p{block=Musical_Symbols}
            "\xE1\xB4\x90\x30" => '\u1d100',
            "\xE1\xB4\x90\x31" => '\u1d101',
            "\xE1\xB4\x90\x32" => '\u1d102',
            "\xE1\xB4\x90\x33" => '\u1d103',
            "\xE1\xB4\x90\x34" => '\u1d104',
            "\xE1\xB4\x90\x35" => '\u1d105',
            "\xE1\xB4\x90\x36" => '\u1d106',
            "\xE1\xB4\x90\x37" => '\u1d107',
            "\xE1\xB4\x90\x38" => '\u1d108',
            "\xE1\xB4\x90\x39" => '\u1d109',
            "\xE1\xB4\x90\x61" => '\u1d10a',
            "\xE1\xB4\x90\x62" => '\u1d10b',
            "\xE1\xB4\x90\x63" => '\u1d10c',
            "\xE1\xB4\x90\x64" => '\u1d10d',
            "\xE1\xB4\x90\x65" => '\u1d10e',
            "\xE1\xB4\x90\x66" => '\u1d10f',
            "\xE1\xB4\x91\x30" => '\u1d110',
            "\xE1\xB4\x91\x31" => '\u1d111',
            "\xE1\xB4\x91\x32" => '\u1d112',
            "\xE1\xB4\x91\x33" => '\u1d113',
            "\xE1\xB4\x91\x34" => '\u1d114',
            "\xE1\xB4\x91\x35" => '\u1d115',
            "\xE1\xB4\x91\x36" => '\u1d116',
            "\xE1\xB4\x91\x37" => '\u1d117',
            "\xE1\xB4\x91\x38" => '\u1d118',
            "\xE1\xB4\x91\x39" => '\u1d119',
            "\xE1\xB4\x91\x61" => '\u1d11a',
            "\xE1\xB4\x91\x62" => '\u1d11b',
            "\xE1\xB4\x91\x63" => '\u1d11c',
            "\xE1\xB4\x91\x64" => '\u1d11d',
            "\xE1\xB4\x91\x65" => '\u1d11e',
            "\xE1\xB4\x91\x66" => '\u1d11f',
            "\xE1\xB4\x92\x30" => '\u1d120',
            "\xE1\xB4\x92\x31" => '\u1d121',
            "\xE1\xB4\x92\x32" => '\u1d122',
            "\xE1\xB4\x92\x33" => '\u1d123',
            "\xE1\xB4\x92\x34" => '\u1d124',
            "\xE1\xB4\x92\x35" => '\u1d125',
            "\xE1\xB4\x92\x36" => '\u1d126',
            "\xE1\xB4\x92\x37" => '\u1d127',
            "\xE1\xB4\x92\x38" => '\u1d128',
            "\xE1\xB4\x92\x39" => '\u1d129',
            "\xE1\xB4\x92\x61" => '\u1d12a',
            "\xE1\xB4\x92\x62" => '\u1d12b',
            "\xE1\xB4\x92\x63" => '\u1d12c',
            "\xE1\xB4\x92\x64" => '\u1d12d',
            "\xE1\xB4\x92\x65" => '\u1d12e',
            "\xE1\xB4\x92\x66" => '\u1d12f',
            "\xE1\xB4\x93\x30" => '\u1d130',
            "\xE1\xB4\x93\x31" => '\u1d131',
            "\xE1\xB4\x93\x32" => '\u1d132',
            "\xE1\xB4\x93\x33" => '\u1d133',
            "\xE1\xB4\x93\x34" => '\u1d134',
            "\xE1\xB4\x93\x35" => '\u1d135',
            "\xE1\xB4\x93\x36" => '\u1d136',
            "\xE1\xB4\x93\x37" => '\u1d137',
            "\xE1\xB4\x93\x38" => '\u1d138',
            "\xE1\xB4\x93\x39" => '\u1d139',
            "\xE1\xB4\x93\x61" => '\u1d13a',
            "\xE1\xB4\x93\x62" => '\u1d13b',
            "\xE1\xB4\x93\x63" => '\u1d13c',
            "\xE1\xB4\x93\x64" => '\u1d13d',
            "\xE1\xB4\x93\x65" => '\u1d13e',
            "\xE1\xB4\x93\x66" => '\u1d13f',
            "\xE1\xB4\x94\x30" => '\u1d140',
            "\xE1\xB4\x94\x31" => '\u1d141',
            "\xE1\xB4\x94\x32" => '\u1d142',
            "\xE1\xB4\x94\x33" => '\u1d143',
            "\xE1\xB4\x94\x34" => '\u1d144',
            "\xE1\xB4\x94\x35" => '\u1d145',
            "\xE1\xB4\x94\x36" => '\u1d146',
            "\xE1\xB4\x94\x37" => '\u1d147',
            "\xE1\xB4\x94\x38" => '\u1d148',
            "\xE1\xB4\x94\x39" => '\u1d149',
            "\xE1\xB4\x94\x61" => '\u1d14a',
            "\xE1\xB4\x94\x62" => '\u1d14b',
            "\xE1\xB4\x94\x63" => '\u1d14c',
            "\xE1\xB4\x94\x64" => '\u1d14d',
            "\xE1\xB4\x94\x65" => '\u1d14e',
            "\xE1\xB4\x94\x66" => '\u1d14f',
            "\xE1\xB4\x95\x30" => '\u1d150',
            "\xE1\xB4\x95\x31" => '\u1d151',
            "\xE1\xB4\x95\x32" => '\u1d152',
            "\xE1\xB4\x95\x33" => '\u1d153',
            "\xE1\xB4\x95\x34" => '\u1d154',
            "\xE1\xB4\x95\x35" => '\u1d155',
            "\xE1\xB4\x95\x36" => '\u1d156',
            "\xE1\xB4\x95\x37" => '\u1d157',
            "\xE1\xB4\x95\x38" => '\u1d158',
            "\xE1\xB4\x95\x39" => '\u1d159',
            "\xE1\xB4\x95\x61" => '\u1d15a',
            "\xE1\xB4\x95\x62" => '\u1d15b',
            "\xE1\xB4\x95\x63" => '\u1d15c',
            "\xE1\xB4\x95\x64" => '\u1d15d',
            "\xE1\xB4\x95\x65" => '\u1d15e',
            "\xE1\xB4\x95\x66" => '\u1d15f',
            "\xE1\xB4\x96\x30" => '\u1d160',
            "\xE1\xB4\x96\x31" => '\u1d161',
            "\xE1\xB4\x96\x32" => '\u1d162',
            "\xE1\xB4\x96\x33" => '\u1d163',
            "\xE1\xB4\x96\x34" => '\u1d164',
            "\xE1\xB4\x96\x35" => '\u1d165',
            "\xE1\xB4\x96\x36" => '\u1d166',
            "\xE1\xB4\x96\x37" => '\u1d167',
            "\xE1\xB4\x96\x38" => '\u1d168',
            "\xE1\xB4\x96\x39" => '\u1d169',
            "\xE1\xB4\x96\x61" => '\u1d16a',
            "\xE1\xB4\x96\x62" => '\u1d16b',
            "\xE1\xB4\x96\x63" => '\u1d16c',
            "\xE1\xB4\x96\x64" => '\u1d16d',
            "\xE1\xB4\x96\x65" => '\u1d16e',
            "\xE1\xB4\x96\x66" => '\u1d16f',
            "\xE1\xB4\x97\x30" => '\u1d170',
            "\xE1\xB4\x97\x31" => '\u1d171',
            "\xE1\xB4\x97\x32" => '\u1d172',
            "\xE1\xB4\x97\x33" => '\u1d173',
            "\xE1\xB4\x97\x34" => '\u1d174',
            "\xE1\xB4\x97\x35" => '\u1d175',
            "\xE1\xB4\x97\x36" => '\u1d176',
            "\xE1\xB4\x97\x37" => '\u1d177',
            "\xE1\xB4\x97\x38" => '\u1d178',
            "\xE1\xB4\x97\x39" => '\u1d179',
            "\xE1\xB4\x97\x61" => '\u1d17a',
            "\xE1\xB4\x97\x62" => '\u1d17b',
            "\xE1\xB4\x97\x63" => '\u1d17c',
            "\xE1\xB4\x97\x64" => '\u1d17d',
            "\xE1\xB4\x97\x65" => '\u1d17e',
            "\xE1\xB4\x97\x66" => '\u1d17f',
            "\xE1\xB4\x98\x30" => '\u1d180',
            "\xE1\xB4\x98\x31" => '\u1d181',
            "\xE1\xB4\x98\x32" => '\u1d182',
            "\xE1\xB4\x98\x33" => '\u1d183',
            "\xE1\xB4\x98\x34" => '\u1d184',
            "\xE1\xB4\x98\x35" => '\u1d185',
            "\xE1\xB4\x98\x36" => '\u1d186',
            "\xE1\xB4\x98\x37" => '\u1d187',
            "\xE1\xB4\x98\x38" => '\u1d188',
            "\xE1\xB4\x98\x39" => '\u1d189',
            "\xE1\xB4\x98\x61" => '\u1d18a',
            "\xE1\xB4\x98\x62" => '\u1d18b',
            "\xE1\xB4\x98\x63" => '\u1d18c',
            "\xE1\xB4\x98\x64" => '\u1d18d',
            "\xE1\xB4\x98\x65" => '\u1d18e',
            "\xE1\xB4\x98\x66" => '\u1d18f',
            "\xE1\xB4\x99\x30" => '\u1d190',
            "\xE1\xB4\x99\x31" => '\u1d191',
            "\xE1\xB4\x99\x32" => '\u1d192',
            "\xE1\xB4\x99\x33" => '\u1d193',
            "\xE1\xB4\x99\x34" => '\u1d194',
            "\xE1\xB4\x99\x35" => '\u1d195',
            "\xE1\xB4\x99\x36" => '\u1d196',
            "\xE1\xB4\x99\x37" => '\u1d197',
            "\xE1\xB4\x99\x38" => '\u1d198',
            "\xE1\xB4\x99\x39" => '\u1d199',
            "\xE1\xB4\x99\x61" => '\u1d19a',
            "\xE1\xB4\x99\x62" => '\u1d19b',
            "\xE1\xB4\x99\x63" => '\u1d19c',
            "\xE1\xB4\x99\x64" => '\u1d19d',
            "\xE1\xB4\x99\x65" => '\u1d19e',
            "\xE1\xB4\x99\x66" => '\u1d19f',
            "\xE1\xB4\x9A\x30" => '\u1d1a0',
            "\xE1\xB4\x9A\x31" => '\u1d1a1',
            "\xE1\xB4\x9A\x32" => '\u1d1a2',
            "\xE1\xB4\x9A\x33" => '\u1d1a3',
            "\xE1\xB4\x9A\x34" => '\u1d1a4',
            "\xE1\xB4\x9A\x35" => '\u1d1a5',
            "\xE1\xB4\x9A\x36" => '\u1d1a6',
            "\xE1\xB4\x9A\x37" => '\u1d1a7',
            "\xE1\xB4\x9A\x38" => '\u1d1a8',
            "\xE1\xB4\x9A\x39" => '\u1d1a9',
            "\xE1\xB4\x9A\x61" => '\u1d1aa',
            "\xE1\xB4\x9A\x62" => '\u1d1ab',
            "\xE1\xB4\x9A\x63" => '\u1d1ac',
            "\xE1\xB4\x9A\x64" => '\u1d1ad',
            "\xE1\xB4\x9A\x65" => '\u1d1ae',
            "\xE1\xB4\x9A\x66" => '\u1d1af',
            "\xE1\xB4\x9B\x30" => '\u1d1b0',
            "\xE1\xB4\x9B\x31" => '\u1d1b1',
            "\xE1\xB4\x9B\x32" => '\u1d1b2',
            "\xE1\xB4\x9B\x33" => '\u1d1b3',
            "\xE1\xB4\x9B\x34" => '\u1d1b4',
            "\xE1\xB4\x9B\x35" => '\u1d1b5',
            "\xE1\xB4\x9B\x36" => '\u1d1b6',
            "\xE1\xB4\x9B\x37" => '\u1d1b7',
            "\xE1\xB4\x9B\x38" => '\u1d1b8',
            "\xE1\xB4\x9B\x39" => '\u1d1b9',
            "\xE1\xB4\x9B\x61" => '\u1d1ba',
            "\xE1\xB4\x9B\x62" => '\u1d1bb',
            "\xE1\xB4\x9B\x63" => '\u1d1bc',
            "\xE1\xB4\x9B\x64" => '\u1d1bd',
            "\xE1\xB4\x9B\x65" => '\u1d1be',
            "\xE1\xB4\x9B\x66" => '\u1d1bf',
            "\xE1\xB4\x9C\x30" => '\u1d1c0',
            "\xE1\xB4\x9C\x31" => '\u1d1c1',
            "\xE1\xB4\x9C\x32" => '\u1d1c2',
            "\xE1\xB4\x9C\x33" => '\u1d1c3',
            "\xE1\xB4\x9C\x34" => '\u1d1c4',
            "\xE1\xB4\x9C\x35" => '\u1d1c5',
            "\xE1\xB4\x9C\x36" => '\u1d1c6',
            "\xE1\xB4\x9C\x37" => '\u1d1c7',
            "\xE1\xB4\x9C\x38" => '\u1d1c8',
            "\xE1\xB4\x9C\x39" => '\u1d1c9',
            "\xE1\xB4\x9C\x61" => '\u1d1ca',
            "\xE1\xB4\x9C\x62" => '\u1d1cb',
            "\xE1\xB4\x9C\x63" => '\u1d1cc',
            "\xE1\xB4\x9C\x64" => '\u1d1cd',
            "\xE1\xB4\x9C\x65" => '\u1d1ce',
            "\xE1\xB4\x9C\x66" => '\u1d1cf',
            "\xE1\xB4\x9D\x30" => '\u1d1d0',
            "\xE1\xB4\x9D\x31" => '\u1d1d1',
            "\xE1\xB4\x9D\x32" => '\u1d1d2',
            "\xE1\xB4\x9D\x33" => '\u1d1d3',
            "\xE1\xB4\x9D\x34" => '\u1d1d4',
            "\xE1\xB4\x9D\x35" => '\u1d1d5',
            "\xE1\xB4\x9D\x36" => '\u1d1d6',
            "\xE1\xB4\x9D\x37" => '\u1d1d7',
            "\xE1\xB4\x9D\x38" => '\u1d1d8',
            "\xE1\xB4\x9D\x39" => '\u1d1d9',
            "\xE1\xB4\x9D\x61" => '\u1d1da',
            "\xE1\xB4\x9D\x62" => '\u1d1db',
            "\xE1\xB4\x9D\x63" => '\u1d1dc',
            "\xE1\xB4\x9D\x64" => '\u1d1dd',
            "\xE1\xB4\x9D\x65" => '\u1d1de',
            "\xE1\xB4\x9D\x66" => '\u1d1df',
            "\xE1\xB4\x9E\x30" => '\u1d1e0',
            "\xE1\xB4\x9E\x31" => '\u1d1e1',
            "\xE1\xB4\x9E\x32" => '\u1d1e2',
            "\xE1\xB4\x9E\x33" => '\u1d1e3',
            "\xE1\xB4\x9E\x34" => '\u1d1e4',
            "\xE1\xB4\x9E\x35" => '\u1d1e5',
            "\xE1\xB4\x9E\x36" => '\u1d1e6',
            "\xE1\xB4\x9E\x37" => '\u1d1e7',
            "\xE1\xB4\x9E\x38" => '\u1d1e8',
            "\xE1\xB4\x9E\x39" => '\u1d1e9',
            "\xE1\xB4\x9E\x61" => '\u1d1ea',
            "\xE1\xB4\x9E\x62" => '\u1d1eb',
            "\xE1\xB4\x9E\x63" => '\u1d1ec',
            "\xE1\xB4\x9E\x64" => '\u1d1ed',
            "\xE1\xB4\x9E\x65" => '\u1d1ee',
            "\xE1\xB4\x9E\x66" => '\u1d1ef',
            "\xE1\xB4\x9F\x30" => '\u1d1f0',
            "\xE1\xB4\x9F\x31" => '\u1d1f1',
            "\xE1\xB4\x9F\x32" => '\u1d1f2',
            "\xE1\xB4\x9F\x33" => '\u1d1f3',
            "\xE1\xB4\x9F\x34" => '\u1d1f4',
            "\xE1\xB4\x9F\x35" => '\u1d1f5',
            "\xE1\xB4\x9F\x36" => '\u1d1f6',
            "\xE1\xB4\x9F\x37" => '\u1d1f7',
            "\xE1\xB4\x9F\x38" => '\u1d1f8',
            "\xE1\xB4\x9F\x39" => '\u1d1f9',
            "\xE1\xB4\x9F\x61" => '\u1d1fa',
            "\xE1\xB4\x9F\x62" => '\u1d1fb',
            "\xE1\xB4\x9F\x63" => '\u1d1fc',
            "\xE1\xB4\x9F\x64" => '\u1d1fd',
            "\xE1\xB4\x9F\x65" => '\u1d1fe',
            "\xE1\xB4\x9F\x66" => '\u1d1ff',

            // \p{block=Ancient_Greek_Musical_Notation}
            "\xE1\xB4\xA0\x30" => '\u1d200',
            "\xE1\xB4\xA0\x31" => '\u1d201',
            "\xE1\xB4\xA0\x32" => '\u1d202',
            "\xE1\xB4\xA0\x33" => '\u1d203',
            "\xE1\xB4\xA0\x34" => '\u1d204',
            "\xE1\xB4\xA0\x35" => '\u1d205',
            "\xE1\xB4\xA0\x36" => '\u1d206',
            "\xE1\xB4\xA0\x37" => '\u1d207',
            "\xE1\xB4\xA0\x38" => '\u1d208',
            "\xE1\xB4\xA0\x39" => '\u1d209',
            "\xE1\xB4\xA0\x61" => '\u1d20a',
            "\xE1\xB4\xA0\x62" => '\u1d20b',
            "\xE1\xB4\xA0\x63" => '\u1d20c',
            "\xE1\xB4\xA0\x64" => '\u1d20d',
            "\xE1\xB4\xA0\x65" => '\u1d20e',
            "\xE1\xB4\xA0\x66" => '\u1d20f',
            "\xE1\xB4\xA1\x30" => '\u1d210',
            "\xE1\xB4\xA1\x31" => '\u1d211',
            "\xE1\xB4\xA1\x32" => '\u1d212',
            "\xE1\xB4\xA1\x33" => '\u1d213',
            "\xE1\xB4\xA1\x34" => '\u1d214',
            "\xE1\xB4\xA1\x35" => '\u1d215',
            "\xE1\xB4\xA1\x36" => '\u1d216',
            "\xE1\xB4\xA1\x37" => '\u1d217',
            "\xE1\xB4\xA1\x38" => '\u1d218',
            "\xE1\xB4\xA1\x39" => '\u1d219',
            "\xE1\xB4\xA1\x61" => '\u1d21a',
            "\xE1\xB4\xA1\x62" => '\u1d21b',
            "\xE1\xB4\xA1\x63" => '\u1d21c',
            "\xE1\xB4\xA1\x64" => '\u1d21d',
            "\xE1\xB4\xA1\x65" => '\u1d21e',
            "\xE1\xB4\xA1\x66" => '\u1d21f',
            "\xE1\xB4\xA2\x30" => '\u1d220',
            "\xE1\xB4\xA2\x31" => '\u1d221',
            "\xE1\xB4\xA2\x32" => '\u1d222',
            "\xE1\xB4\xA2\x33" => '\u1d223',
            "\xE1\xB4\xA2\x34" => '\u1d224',
            "\xE1\xB4\xA2\x35" => '\u1d225',
            "\xE1\xB4\xA2\x36" => '\u1d226',
            "\xE1\xB4\xA2\x37" => '\u1d227',
            "\xE1\xB4\xA2\x38" => '\u1d228',
            "\xE1\xB4\xA2\x39" => '\u1d229',
            "\xE1\xB4\xA2\x61" => '\u1d22a',
            "\xE1\xB4\xA2\x62" => '\u1d22b',
            "\xE1\xB4\xA2\x63" => '\u1d22c',
            "\xE1\xB4\xA2\x64" => '\u1d22d',
            "\xE1\xB4\xA2\x65" => '\u1d22e',
            "\xE1\xB4\xA2\x66" => '\u1d22f',
            "\xE1\xB4\xA3\x30" => '\u1d230',
            "\xE1\xB4\xA3\x31" => '\u1d231',
            "\xE1\xB4\xA3\x32" => '\u1d232',
            "\xE1\xB4\xA3\x33" => '\u1d233',
            "\xE1\xB4\xA3\x34" => '\u1d234',
            "\xE1\xB4\xA3\x35" => '\u1d235',
            "\xE1\xB4\xA3\x36" => '\u1d236',
            "\xE1\xB4\xA3\x37" => '\u1d237',
            "\xE1\xB4\xA3\x38" => '\u1d238',
            "\xE1\xB4\xA3\x39" => '\u1d239',
            "\xE1\xB4\xA3\x61" => '\u1d23a',
            "\xE1\xB4\xA3\x62" => '\u1d23b',
            "\xE1\xB4\xA3\x63" => '\u1d23c',
            "\xE1\xB4\xA3\x64" => '\u1d23d',
            "\xE1\xB4\xA3\x65" => '\u1d23e',
            "\xE1\xB4\xA3\x66" => '\u1d23f',
            "\xE1\xB4\xA4\x30" => '\u1d240',
            "\xE1\xB4\xA4\x31" => '\u1d241',
            "\xE1\xB4\xA4\x32" => '\u1d242',
            "\xE1\xB4\xA4\x33" => '\u1d243',
            "\xE1\xB4\xA4\x34" => '\u1d244',
            "\xE1\xB4\xA4\x35" => '\u1d245',
            "\xE1\xB4\xA4\x36" => '\u1d246',
            "\xE1\xB4\xA4\x37" => '\u1d247',
            "\xE1\xB4\xA4\x38" => '\u1d248',
            "\xE1\xB4\xA4\x39" => '\u1d249',
            "\xE1\xB4\xA4\x61" => '\u1d24a',
            "\xE1\xB4\xA4\x62" => '\u1d24b',
            "\xE1\xB4\xA4\x63" => '\u1d24c',
            "\xE1\xB4\xA4\x64" => '\u1d24d',
            "\xE1\xB4\xA4\x65" => '\u1d24e',
            "\xE1\xB4\xA4\x66" => '\u1d24f',

        );

        $sanitized = '';
        $pointer = 0;
        while (($char = self::unicodeNextChar($data, $pointer)) !== false) {
            if (isset($excluded[$char])) {
                return 'Invalid character: ' . $excluded[$char];
            }
            $sanitized .= strlen($char) === 1 ? $char : 'a';
        }

        return null;
    }

    /**
     * @see https://stackoverflow.com/a/14366023/329463
     * @param string $string
     * @param int $pointer
     * @return false|string
     */
    private static function unicodeNextChar($string, &$pointer)
    {
        if (!isset($string[$pointer])) return false;
        $char = ord($string[$pointer]);
        if ($char < 128) {
            return $string[$pointer++];
        } else {
            if ($char < 224) {
                $bytes = 2;
            } elseif ($char < 240) {
                $bytes = 3;
            } elseif ($char < 248) {
                $bytes = 4;
            } elseif ($char == 252) {
                $bytes = 5;
            } else {
                $bytes = 6;
            }
            $str = substr($string, $pointer, $bytes);
            $pointer += $bytes;
            return $str;
        }
    }

}