< prev index next >

src/java.base/share/classes/sun/util/locale/LocaleMatcher.java

Print this page




 348 
 349         int splitIndex = splitRanges(priorityList);
 350         List<LanguageRange> nonZeroRanges;
 351         List<LanguageRange> zeroRanges;
 352         if (splitIndex != -1) {
 353             nonZeroRanges = priorityList.subList(0, splitIndex);
 354             zeroRanges = priorityList.subList(splitIndex, priorityList.size());
 355         } else {
 356             nonZeroRanges = priorityList;
 357             zeroRanges = List.of();
 358         }
 359 
 360         for (LanguageRange lr : nonZeroRanges) {
 361             String range = lr.getRange();
 362 
 363             // Special language range ("*") is ignored in lookup.
 364             if (range.equals("*")) {
 365                 continue;
 366             }
 367 
 368             String rangeForRegex = range.replaceAll("\\x2A", "\\\\p{Alnum}*");
 369             while (rangeForRegex.length() > 0) {
 370                 for (String tag : tags) {
 371                     tag = tag.toLowerCase(Locale.ROOT);
 372                     if (tag.matches(rangeForRegex)
 373                             && !shouldIgnoreLookupMatch(zeroRanges, tag)) {
 374                         return tag;
 375                     }
 376                 }
 377 
 378                 // Truncate from the end....
 379                 rangeForRegex = truncateRange(rangeForRegex);
 380             }
 381         }
 382 
 383         return null;
 384     }
 385 
 386     /**
 387      * The tag which is falling in the exclusion range(s) should not be
 388      * considered as the matching tag. Ignores the tag matching with the
 389      * non zero range(s), if the tag also matches with one of the exclusion
 390      * range(s) i.e. range(s) having quality weight q=0.
 391      */
 392     private static boolean shouldIgnoreLookupMatch(List<LanguageRange> zeroRange,
 393             String tag) {
 394         for (LanguageRange lr : zeroRange) {
 395             String range = lr.getRange();
 396 
 397             // Special language range ("*") is ignored in lookup.
 398             if (range.equals("*")) {
 399                 continue;
 400             }
 401 
 402             String rangeForRegex = range.replaceAll("\\x2A", "\\\\p{Alnum}*");
 403             while (rangeForRegex.length() > 0) {
 404                 if (tag.matches(rangeForRegex)) {
 405                     return true;
 406                 }
 407                 // Truncate from the end....
 408                 rangeForRegex = truncateRange(rangeForRegex);
 409             }
 410         }
 411 
 412         return false;
 413     }
 414 
 415     /* Truncate the range from end during the lookup match */
 416     private static String truncateRange(String rangeForRegex) {
 417         int index = rangeForRegex.lastIndexOf('-');
 418         if (index >= 0) {
 419             rangeForRegex = rangeForRegex.substring(0, index);
 420 
 421             // if range ends with an extension key, truncate it.
 422             index = rangeForRegex.lastIndexOf('-');


 430 
 431         return rangeForRegex;
 432     }
 433 
 434     /* Returns the split index of the priority list, if it contains
 435      * language range(s) with quality weight as 0 i.e. q=0, else -1
 436      */
 437     private static int splitRanges(List<LanguageRange> priorityList) {
 438         int size = priorityList.size();
 439         for (int index = 0; index < size; index++) {
 440             LanguageRange range = priorityList.get(index);
 441             if (range.getWeight() == 0) {
 442                 return index;
 443             }
 444         }
 445 
 446         return -1; // no q=0 range exists
 447     }
 448 
 449     public static List<LanguageRange> parse(String ranges) {
 450         ranges = ranges.replaceAll(" ", "").toLowerCase(Locale.ROOT);
 451         if (ranges.startsWith("accept-language:")) {
 452             ranges = ranges.substring(16); // delete unnecessary prefix
 453         }
 454 
 455         String[] langRanges = ranges.split(",");
 456         List<LanguageRange> list = new ArrayList<>(langRanges.length);
 457         List<String> tempList = new ArrayList<>();
 458         int numOfRanges = 0;
 459 
 460         for (String range : langRanges) {
 461             int index;
 462             String r;
 463             double w;
 464 
 465             if ((index = range.indexOf(";q=")) == -1) {
 466                 r = range;
 467                 w = MAX_WEIGHT;
 468             } else {
 469                 r = range.substring(0, index);
 470                 index += 3;


 519                             numOfRanges++;
 520                             tempList.add(equiv);
 521                         }
 522 
 523                         // bb-XX -> bb-YY(, cc-YY)
 524                         equivalent = getEquivalentForRegionAndVariant(equiv);
 525                         if (equivalent != null
 526                             && !tempList.contains(equivalent)) {
 527                             list.add(index+1, new LanguageRange(equivalent, w));
 528                             numOfRanges++;
 529                             tempList.add(equivalent);
 530                         }
 531                     }
 532                 }
 533             }
 534         }
 535 
 536         return list;
 537     }
 538 















 539     private static String[] getEquivalentsForLanguage(String range) {
 540         String r = range;
 541 
 542         while (r.length() > 0) {
 543             if (LocaleEquivalentMaps.singleEquivMap.containsKey(r)) {
 544                 String equiv = LocaleEquivalentMaps.singleEquivMap.get(r);
 545                 // Return immediately for performance if the first matching
 546                 // subtag is found.
 547                 return new String[] {range.replaceFirst(r, equiv)};

 548             } else if (LocaleEquivalentMaps.multiEquivsMap.containsKey(r)) {
 549                 String[] equivs = LocaleEquivalentMaps.multiEquivsMap.get(r);

 550                 for (int i = 0; i < equivs.length; i++) {
 551                     equivs[i] = range.replaceFirst(r, equivs[i]);

 552                 }
 553                 return equivs;
 554             }
 555 
 556             // Truncate the last subtag simply.
 557             int index = r.lastIndexOf('-');
 558             if (index == -1) {
 559                 break;
 560             }
 561             r = r.substring(0, index);
 562         }
 563 
 564         return null;
 565     }
 566 
 567     private static String getEquivalentForRegionAndVariant(String range) {
 568         int extensionKeyIndex = getExtentionKeyIndex(range);
 569 
 570         for (String subtag : LocaleEquivalentMaps.regionVariantEquivMap.keySet()) {
 571             int index;
 572             if ((index = range.indexOf(subtag)) != -1) {
 573                 // Check if the matching text is a valid region or variant.
 574                 if (extensionKeyIndex != Integer.MIN_VALUE
 575                     && index > extensionKeyIndex) {
 576                     continue;
 577                 }
 578 
 579                 int len = index + subtag.length();
 580                 if (range.length() == len || range.charAt(len) == '-') {
 581                     return range.replaceFirst(subtag, LocaleEquivalentMaps.regionVariantEquivMap.get(subtag));


 582                 }
 583             }
 584         }
 585 
 586         return null;
 587     }
 588 
 589     private static int getExtentionKeyIndex(String s) {
 590         char[] c = s.toCharArray();
 591         int index = Integer.MIN_VALUE;
 592         for (int i = 1; i < c.length; i++) {
 593             if (c[i] == '-') {
 594                 if (i - index == 2) {
 595                     return index;
 596                 } else {
 597                     index = i;
 598                 }
 599             }
 600         }
 601         return Integer.MIN_VALUE;




 348 
 349         int splitIndex = splitRanges(priorityList);
 350         List<LanguageRange> nonZeroRanges;
 351         List<LanguageRange> zeroRanges;
 352         if (splitIndex != -1) {
 353             nonZeroRanges = priorityList.subList(0, splitIndex);
 354             zeroRanges = priorityList.subList(splitIndex, priorityList.size());
 355         } else {
 356             nonZeroRanges = priorityList;
 357             zeroRanges = List.of();
 358         }
 359 
 360         for (LanguageRange lr : nonZeroRanges) {
 361             String range = lr.getRange();
 362 
 363             // Special language range ("*") is ignored in lookup.
 364             if (range.equals("*")) {
 365                 continue;
 366             }
 367 
 368             String rangeForRegex = range.replace("*", "\\p{Alnum}*");
 369             while (rangeForRegex.length() > 0) {
 370                 for (String tag : tags) {
 371                     tag = tag.toLowerCase(Locale.ROOT);
 372                     if (tag.matches(rangeForRegex)
 373                             && !shouldIgnoreLookupMatch(zeroRanges, tag)) {
 374                         return tag;
 375                     }
 376                 }
 377 
 378                 // Truncate from the end....
 379                 rangeForRegex = truncateRange(rangeForRegex);
 380             }
 381         }
 382 
 383         return null;
 384     }
 385 
 386     /**
 387      * The tag which is falling in the exclusion range(s) should not be
 388      * considered as the matching tag. Ignores the tag matching with the
 389      * non zero range(s), if the tag also matches with one of the exclusion
 390      * range(s) i.e. range(s) having quality weight q=0.
 391      */
 392     private static boolean shouldIgnoreLookupMatch(List<LanguageRange> zeroRange,
 393             String tag) {
 394         for (LanguageRange lr : zeroRange) {
 395             String range = lr.getRange();
 396 
 397             // Special language range ("*") is ignored in lookup.
 398             if (range.equals("*")) {
 399                 continue;
 400             }
 401 
 402             String rangeForRegex = range.replace("*", "\\p{Alnum}*");
 403             while (rangeForRegex.length() > 0) {
 404                 if (tag.matches(rangeForRegex)) {
 405                     return true;
 406                 }
 407                 // Truncate from the end....
 408                 rangeForRegex = truncateRange(rangeForRegex);
 409             }
 410         }
 411 
 412         return false;
 413     }
 414 
 415     /* Truncate the range from end during the lookup match */
 416     private static String truncateRange(String rangeForRegex) {
 417         int index = rangeForRegex.lastIndexOf('-');
 418         if (index >= 0) {
 419             rangeForRegex = rangeForRegex.substring(0, index);
 420 
 421             // if range ends with an extension key, truncate it.
 422             index = rangeForRegex.lastIndexOf('-');


 430 
 431         return rangeForRegex;
 432     }
 433 
 434     /* Returns the split index of the priority list, if it contains
 435      * language range(s) with quality weight as 0 i.e. q=0, else -1
 436      */
 437     private static int splitRanges(List<LanguageRange> priorityList) {
 438         int size = priorityList.size();
 439         for (int index = 0; index < size; index++) {
 440             LanguageRange range = priorityList.get(index);
 441             if (range.getWeight() == 0) {
 442                 return index;
 443             }
 444         }
 445 
 446         return -1; // no q=0 range exists
 447     }
 448 
 449     public static List<LanguageRange> parse(String ranges) {
 450         ranges = ranges.replace(" ", "").toLowerCase(Locale.ROOT);
 451         if (ranges.startsWith("accept-language:")) {
 452             ranges = ranges.substring(16); // delete unnecessary prefix
 453         }
 454 
 455         String[] langRanges = ranges.split(",");
 456         List<LanguageRange> list = new ArrayList<>(langRanges.length);
 457         List<String> tempList = new ArrayList<>();
 458         int numOfRanges = 0;
 459 
 460         for (String range : langRanges) {
 461             int index;
 462             String r;
 463             double w;
 464 
 465             if ((index = range.indexOf(";q=")) == -1) {
 466                 r = range;
 467                 w = MAX_WEIGHT;
 468             } else {
 469                 r = range.substring(0, index);
 470                 index += 3;


 519                             numOfRanges++;
 520                             tempList.add(equiv);
 521                         }
 522 
 523                         // bb-XX -> bb-YY(, cc-YY)
 524                         equivalent = getEquivalentForRegionAndVariant(equiv);
 525                         if (equivalent != null
 526                             && !tempList.contains(equivalent)) {
 527                             list.add(index+1, new LanguageRange(equivalent, w));
 528                             numOfRanges++;
 529                             tempList.add(equivalent);
 530                         }
 531                     }
 532                 }
 533             }
 534         }
 535 
 536         return list;
 537     }
 538 
 539     /**
 540      * A faster alternative approach to String.replaceFirst(), if the given
 541      * string is a literal String, not a regex.
 542      */
 543     private static String replaceFirstSubStringMatch(String range,
 544             String substr, String replacement) {
 545         int pos = range.indexOf(substr);
 546         if (pos == -1) {
 547             return range;
 548         } else {
 549             return range.substring(0, pos) + replacement
 550                     + range.substring(pos + substr.length());
 551         }
 552     }
 553 
 554     private static String[] getEquivalentsForLanguage(String range) {
 555         String r = range;
 556 
 557         while (r.length() > 0) {
 558             if (LocaleEquivalentMaps.singleEquivMap.containsKey(r)) {
 559                 String equiv = LocaleEquivalentMaps.singleEquivMap.get(r);
 560                 // Return immediately for performance if the first matching
 561                 // subtag is found.
 562                 return new String[]{replaceFirstSubStringMatch(range,
 563                     r, equiv)};
 564             } else if (LocaleEquivalentMaps.multiEquivsMap.containsKey(r)) {
 565                 String[] equivs = LocaleEquivalentMaps.multiEquivsMap.get(r);
 566                 String[] result = new String[equivs.length];
 567                 for (int i = 0; i < equivs.length; i++) {
 568                     result[i] = replaceFirstSubStringMatch(range,
 569                             r, equivs[i]);
 570                 }
 571                 return result;
 572             }
 573 
 574             // Truncate the last subtag simply.
 575             int index = r.lastIndexOf('-');
 576             if (index == -1) {
 577                 break;
 578             }
 579             r = r.substring(0, index);
 580         }
 581 
 582         return null;
 583     }
 584 
 585     private static String getEquivalentForRegionAndVariant(String range) {
 586         int extensionKeyIndex = getExtentionKeyIndex(range);
 587 
 588         for (String subtag : LocaleEquivalentMaps.regionVariantEquivMap.keySet()) {
 589             int index;
 590             if ((index = range.indexOf(subtag)) != -1) {
 591                 // Check if the matching text is a valid region or variant.
 592                 if (extensionKeyIndex != Integer.MIN_VALUE
 593                     && index > extensionKeyIndex) {
 594                     continue;
 595                 }
 596 
 597                 int len = index + subtag.length();
 598                 if (range.length() == len || range.charAt(len) == '-') {
 599                     return replaceFirstSubStringMatch(range, subtag,
 600                             LocaleEquivalentMaps.regionVariantEquivMap
 601                                     .get(subtag));
 602                 }
 603             }
 604         }
 605 
 606         return null;
 607     }
 608 
 609     private static int getExtentionKeyIndex(String s) {
 610         char[] c = s.toCharArray();
 611         int index = Integer.MIN_VALUE;
 612         for (int i = 1; i < c.length; i++) {
 613             if (c[i] == '-') {
 614                 if (i - index == 2) {
 615                     return index;
 616                 } else {
 617                     index = i;
 618                 }
 619             }
 620         }
 621         return Integer.MIN_VALUE;


< prev index next >