Home | History | Annotate | Download | only in text
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  * http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     14  * License for the specific language governing permissions and limitations under
     15  * the License.
     16  */
     17 
     18 package java.text;
     19 
     20 import java.text.AttributedCharacterIterator.Attribute;
     21 import java.util.ArrayList;
     22 import java.util.Arrays;
     23 import java.util.HashMap;
     24 import java.util.HashSet;
     25 import java.util.Iterator;
     26 import java.util.List;
     27 import java.util.ListIterator;
     28 import java.util.Map;
     29 import java.util.Set;
     30 
     31 /**
     32  * Holds a string with attributes describing the characters of
     33  * this string.
     34  */
     35 public class AttributedString {
     36 
     37     String text;
     38 
     39     Map<AttributedCharacterIterator.Attribute, List<Range>> attributeMap;
     40 
     41     static class Range {
     42         int start;
     43 
     44         int end;
     45 
     46         Object value;
     47 
     48         Range(int s, int e, Object v) {
     49             start = s;
     50             end = e;
     51             value = v;
     52         }
     53     }
     54 
     55     static class AttributedIterator implements AttributedCharacterIterator {
     56 
     57         private int begin, end, offset;
     58 
     59         private AttributedString attrString;
     60 
     61         private HashSet<Attribute> attributesAllowed;
     62 
     63         AttributedIterator(AttributedString attrString) {
     64             this.attrString = attrString;
     65             begin = 0;
     66             end = attrString.text.length();
     67             offset = 0;
     68         }
     69 
     70         AttributedIterator(AttributedString attrString,
     71                 AttributedCharacterIterator.Attribute[] attributes, int begin,
     72                 int end) {
     73             if (begin < 0 || end > attrString.text.length() || begin > end) {
     74                 throw new IllegalArgumentException();
     75             }
     76             this.begin = begin;
     77             this.end = end;
     78             offset = begin;
     79             this.attrString = attrString;
     80             if (attributes != null) {
     81                 HashSet<Attribute> set = new HashSet<Attribute>(
     82                         (attributes.length * 4 / 3) + 1);
     83                 for (int i = attributes.length; --i >= 0;) {
     84                     set.add(attributes[i]);
     85                 }
     86                 attributesAllowed = set;
     87             }
     88         }
     89 
     90         /**
     91          * Returns a new {@code AttributedIterator} with the same source string,
     92          * begin, end, and current index as this attributed iterator.
     93          *
     94          * @return a shallow copy of this attributed iterator.
     95          * @see java.lang.Cloneable
     96          */
     97         @Override
     98         @SuppressWarnings("unchecked")
     99         public Object clone() {
    100             try {
    101                 AttributedIterator clone = (AttributedIterator) super.clone();
    102                 if (attributesAllowed != null) {
    103                     clone.attributesAllowed = (HashSet<Attribute>) attributesAllowed
    104                             .clone();
    105                 }
    106                 return clone;
    107             } catch (CloneNotSupportedException e) {
    108                 throw new AssertionError(e);
    109             }
    110         }
    111 
    112         public char current() {
    113             if (offset == end) {
    114                 return DONE;
    115             }
    116             return attrString.text.charAt(offset);
    117         }
    118 
    119         public char first() {
    120             if (begin == end) {
    121                 return DONE;
    122             }
    123             offset = begin;
    124             return attrString.text.charAt(offset);
    125         }
    126 
    127         /**
    128          * Returns the begin index in the source string.
    129          *
    130          * @return the index of the first character to iterate.
    131          */
    132         public int getBeginIndex() {
    133             return begin;
    134         }
    135 
    136         /**
    137          * Returns the end index in the source String.
    138          *
    139          * @return the index one past the last character to iterate.
    140          */
    141         public int getEndIndex() {
    142             return end;
    143         }
    144 
    145         /**
    146          * Returns the current index in the source String.
    147          *
    148          * @return the current index.
    149          */
    150         public int getIndex() {
    151             return offset;
    152         }
    153 
    154         private boolean inRange(Range range) {
    155             if (!(range.value instanceof Annotation)) {
    156                 return true;
    157             }
    158             return range.start >= begin && range.start < end
    159                     && range.end > begin && range.end <= end;
    160         }
    161 
    162         private boolean inRange(List<Range> ranges) {
    163             Iterator<Range> it = ranges.iterator();
    164             while (it.hasNext()) {
    165                 Range range = it.next();
    166                 if (range.start >= begin && range.start < end) {
    167                     return !(range.value instanceof Annotation)
    168                             || (range.end > begin && range.end <= end);
    169                 } else if (range.end > begin && range.end <= end) {
    170                     return !(range.value instanceof Annotation)
    171                             || (range.start >= begin && range.start < end);
    172                 }
    173             }
    174             return false;
    175         }
    176 
    177         /**
    178          * Returns a set of attributes present in the {@code AttributedString}.
    179          * An empty set returned indicates that no attributes where defined.
    180          *
    181          * @return a set of attribute keys that may be empty.
    182          */
    183         public Set<AttributedIterator.Attribute> getAllAttributeKeys() {
    184             if (begin == 0 && end == attrString.text.length()
    185                     && attributesAllowed == null) {
    186                 return attrString.attributeMap.keySet();
    187             }
    188 
    189             Set<AttributedIterator.Attribute> result = new HashSet<Attribute>(
    190                     (attrString.attributeMap.size() * 4 / 3) + 1);
    191             Iterator<Map.Entry<Attribute, List<Range>>> it = attrString.attributeMap
    192                     .entrySet().iterator();
    193             while (it.hasNext()) {
    194                 Map.Entry<Attribute, List<Range>> entry = it.next();
    195                 if (attributesAllowed == null
    196                         || attributesAllowed.contains(entry.getKey())) {
    197                     List<Range> ranges = entry.getValue();
    198                     if (inRange(ranges)) {
    199                         result.add(entry.getKey());
    200                     }
    201                 }
    202             }
    203             return result;
    204         }
    205 
    206         private Object currentValue(List<Range> ranges) {
    207             Iterator<Range> it = ranges.iterator();
    208             while (it.hasNext()) {
    209                 Range range = it.next();
    210                 if (offset >= range.start && offset < range.end) {
    211                     return inRange(range) ? range.value : null;
    212                 }
    213             }
    214             return null;
    215         }
    216 
    217         public Object getAttribute(
    218                 AttributedCharacterIterator.Attribute attribute) {
    219             if (attributesAllowed != null
    220                     && !attributesAllowed.contains(attribute)) {
    221                 return null;
    222             }
    223             ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
    224                     .get(attribute);
    225             if (ranges == null) {
    226                 return null;
    227             }
    228             return currentValue(ranges);
    229         }
    230 
    231         public Map<Attribute, Object> getAttributes() {
    232             Map<Attribute, Object> result = new HashMap<Attribute, Object>(
    233                     (attrString.attributeMap.size() * 4 / 3) + 1);
    234             Iterator<Map.Entry<Attribute, List<Range>>> it = attrString.attributeMap
    235                     .entrySet().iterator();
    236             while (it.hasNext()) {
    237                 Map.Entry<Attribute, List<Range>> entry = it.next();
    238                 if (attributesAllowed == null
    239                         || attributesAllowed.contains(entry.getKey())) {
    240                     Object value = currentValue(entry.getValue());
    241                     if (value != null) {
    242                         result.put(entry.getKey(), value);
    243                     }
    244                 }
    245             }
    246             return result;
    247         }
    248 
    249         public int getRunLimit() {
    250             return getRunLimit(getAllAttributeKeys());
    251         }
    252 
    253         private int runLimit(List<Range> ranges) {
    254             int result = end;
    255             ListIterator<Range> it = ranges.listIterator(ranges.size());
    256             while (it.hasPrevious()) {
    257                 Range range = it.previous();
    258                 if (range.end <= begin) {
    259                     break;
    260                 }
    261                 if (offset >= range.start && offset < range.end) {
    262                     return inRange(range) ? range.end : result;
    263                 } else if (offset >= range.end) {
    264                     break;
    265                 }
    266                 result = range.start;
    267             }
    268             return result;
    269         }
    270 
    271         public int getRunLimit(AttributedCharacterIterator.Attribute attribute) {
    272             if (attributesAllowed != null
    273                     && !attributesAllowed.contains(attribute)) {
    274                 return end;
    275             }
    276             ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
    277                     .get(attribute);
    278             if (ranges == null) {
    279                 return end;
    280             }
    281             return runLimit(ranges);
    282         }
    283 
    284         public int getRunLimit(Set<? extends Attribute> attributes) {
    285             int limit = end;
    286             Iterator<? extends Attribute> it = attributes.iterator();
    287             while (it.hasNext()) {
    288                 AttributedCharacterIterator.Attribute attribute = it.next();
    289                 int newLimit = getRunLimit(attribute);
    290                 if (newLimit < limit) {
    291                     limit = newLimit;
    292                 }
    293             }
    294             return limit;
    295         }
    296 
    297         public int getRunStart() {
    298             return getRunStart(getAllAttributeKeys());
    299         }
    300 
    301         private int runStart(List<Range> ranges) {
    302             int result = begin;
    303             Iterator<Range> it = ranges.iterator();
    304             while (it.hasNext()) {
    305                 Range range = it.next();
    306                 if (range.start >= end) {
    307                     break;
    308                 }
    309                 if (offset >= range.start && offset < range.end) {
    310                     return inRange(range) ? range.start : result;
    311                 } else if (offset < range.start) {
    312                     break;
    313                 }
    314                 result = range.end;
    315             }
    316             return result;
    317         }
    318 
    319         public int getRunStart(AttributedCharacterIterator.Attribute attribute) {
    320             if (attributesAllowed != null
    321                     && !attributesAllowed.contains(attribute)) {
    322                 return begin;
    323             }
    324             ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
    325                     .get(attribute);
    326             if (ranges == null) {
    327                 return begin;
    328             }
    329             return runStart(ranges);
    330         }
    331 
    332         public int getRunStart(Set<? extends Attribute> attributes) {
    333             int start = begin;
    334             Iterator<? extends Attribute> it = attributes.iterator();
    335             while (it.hasNext()) {
    336                 AttributedCharacterIterator.Attribute attribute = it.next();
    337                 int newStart = getRunStart(attribute);
    338                 if (newStart > start) {
    339                     start = newStart;
    340                 }
    341             }
    342             return start;
    343         }
    344 
    345         public char last() {
    346             if (begin == end) {
    347                 return DONE;
    348             }
    349             offset = end - 1;
    350             return attrString.text.charAt(offset);
    351         }
    352 
    353         public char next() {
    354             if (offset >= (end - 1)) {
    355                 offset = end;
    356                 return DONE;
    357             }
    358             return attrString.text.charAt(++offset);
    359         }
    360 
    361         public char previous() {
    362             if (offset == begin) {
    363                 return DONE;
    364             }
    365             return attrString.text.charAt(--offset);
    366         }
    367 
    368         public char setIndex(int location) {
    369             if (location < begin || location > end) {
    370                 throw new IllegalArgumentException();
    371             }
    372             offset = location;
    373             if (offset == end) {
    374                 return DONE;
    375             }
    376             return attrString.text.charAt(offset);
    377         }
    378     }
    379 
    380     /**
    381      * Constructs an {@code AttributedString} from an {@code
    382      * AttributedCharacterIterator}, which represents attributed text.
    383      *
    384      * @param iterator
    385      *            the {@code AttributedCharacterIterator} that contains the text
    386      *            for this attributed string.
    387      */
    388     public AttributedString(AttributedCharacterIterator iterator) {
    389         if (iterator.getBeginIndex() > iterator.getEndIndex()) {
    390             throw new IllegalArgumentException("Invalid substring range");
    391         }
    392         StringBuilder buffer = new StringBuilder();
    393         for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex(); i++) {
    394             buffer.append(iterator.current());
    395             iterator.next();
    396         }
    397         text = buffer.toString();
    398         Set<AttributedCharacterIterator.Attribute> attributes = iterator
    399                 .getAllAttributeKeys();
    400         if (attributes == null) {
    401             return;
    402         }
    403         attributeMap = new HashMap<Attribute, List<Range>>(
    404                 (attributes.size() * 4 / 3) + 1);
    405 
    406         Iterator<Attribute> it = attributes.iterator();
    407         while (it.hasNext()) {
    408             AttributedCharacterIterator.Attribute attribute = it.next();
    409             iterator.setIndex(0);
    410             while (iterator.current() != CharacterIterator.DONE) {
    411                 int start = iterator.getRunStart(attribute);
    412                 int limit = iterator.getRunLimit(attribute);
    413                 Object value = iterator.getAttribute(attribute);
    414                 if (value != null) {
    415                     addAttribute(attribute, value, start, limit);
    416                 }
    417                 iterator.setIndex(limit);
    418             }
    419         }
    420     }
    421 
    422     private AttributedString(AttributedCharacterIterator iterator, int start,
    423             int end, Set<Attribute> attributes) {
    424         if (start < iterator.getBeginIndex() || end > iterator.getEndIndex()
    425                 || start > end) {
    426             throw new IllegalArgumentException();
    427         }
    428 
    429         if (attributes == null) {
    430             return;
    431         }
    432 
    433         StringBuilder buffer = new StringBuilder();
    434         iterator.setIndex(start);
    435         while (iterator.getIndex() < end) {
    436             buffer.append(iterator.current());
    437             iterator.next();
    438         }
    439         text = buffer.toString();
    440         attributeMap = new HashMap<Attribute, List<Range>>(
    441                 (attributes.size() * 4 / 3) + 1);
    442 
    443         Iterator<Attribute> it = attributes.iterator();
    444         while (it.hasNext()) {
    445             AttributedCharacterIterator.Attribute attribute = it.next();
    446             iterator.setIndex(start);
    447             while (iterator.getIndex() < end) {
    448                 Object value = iterator.getAttribute(attribute);
    449                 int runStart = iterator.getRunStart(attribute);
    450                 int limit = iterator.getRunLimit(attribute);
    451                 if ((value instanceof Annotation && runStart >= start && limit <= end)
    452                         || (value != null && !(value instanceof Annotation))) {
    453                     addAttribute(attribute, value, (runStart < start ? start
    454                             : runStart)
    455                             - start, (limit > end ? end : limit) - start);
    456                 }
    457                 iterator.setIndex(limit);
    458             }
    459         }
    460     }
    461 
    462     /**
    463      * Constructs an {@code AttributedString} from a range of the text contained
    464      * in the specified {@code AttributedCharacterIterator}, starting at {@code
    465      * start} and ending at {@code end}. All attributes will be copied to this
    466      * attributed string.
    467      *
    468      * @param iterator
    469      *            the {@code AttributedCharacterIterator} that contains the text
    470      *            for this attributed string.
    471      * @param start
    472      *            the start index of the range of the copied text.
    473      * @param end
    474      *            the end index of the range of the copied text.
    475      * @throws IllegalArgumentException
    476      *             if {@code start} is less than first index of
    477      *             {@code iterator}, {@code end} is greater than the last
    478      *             index + 1 in {@code iterator} or if {@code start > end}.
    479      */
    480     public AttributedString(AttributedCharacterIterator iterator, int start,
    481             int end) {
    482         this(iterator, start, end, iterator.getAllAttributeKeys());
    483     }
    484 
    485     /**
    486      * Constructs an {@code AttributedString} from a range of the text contained
    487      * in the specified {@code AttributedCharacterIterator}, starting at {@code
    488      * start}, ending at {@code end} and it will copy the attributes defined in
    489      * the specified set. If the set is {@code null} then all attributes are
    490      * copied.
    491      *
    492      * @param iterator
    493      *            the {@code AttributedCharacterIterator} that contains the text
    494      *            for this attributed string.
    495      * @param start
    496      *            the start index of the range of the copied text.
    497      * @param end
    498      *            the end index of the range of the copied text.
    499      * @param attributes
    500      *            the set of attributes that will be copied, or all if it is
    501      *            {@code null}.
    502      * @throws IllegalArgumentException
    503      *             if {@code start} is less than first index of
    504      *             {@code iterator}, {@code end} is greater than the last index +
    505      *             1 in {@code iterator} or if {@code start > end}.
    506      */
    507     public AttributedString(AttributedCharacterIterator iterator, int start,
    508             int end, AttributedCharacterIterator.Attribute[] attributes) {
    509         this(iterator, start, end, (attributes == null
    510                 ? new HashSet<Attribute>()
    511                 : new HashSet<Attribute>(Arrays.asList(attributes))));
    512     }
    513 
    514     /**
    515      * Creates an {@code AttributedString} from the given text.
    516      *
    517      * @param value
    518      *            the text to take as base for this attributed string.
    519      */
    520     public AttributedString(String value) {
    521         if (value == null) {
    522             throw new NullPointerException();
    523         }
    524         text = value;
    525         attributeMap = new HashMap<Attribute, List<Range>>(11);
    526     }
    527 
    528     /**
    529      * Creates an {@code AttributedString} from the given text and the
    530      * attributes. The whole text has the given attributes applied.
    531      *
    532      * @param value
    533      *            the text to take as base for this attributed string.
    534      * @param attributes
    535      *            the attributes that the text is associated with.
    536      * @throws IllegalArgumentException
    537      *             if the length of {@code value} is 0 but the size of {@code
    538      *             attributes} is greater than 0.
    539      * @throws NullPointerException
    540      *             if {@code value} is {@code null}.
    541      */
    542     public AttributedString(String value,
    543             Map<? extends AttributedCharacterIterator.Attribute, ?> attributes) {
    544         if (value == null) {
    545             throw new NullPointerException();
    546         }
    547         if (value.length() == 0 && !attributes.isEmpty()) {
    548             throw new IllegalArgumentException("Cannot add attributes to empty string");
    549         }
    550         text = value;
    551         attributeMap = new HashMap<Attribute, List<Range>>(
    552                 (attributes.size() * 4 / 3) + 1);
    553         Iterator<?> it = attributes.entrySet().iterator();
    554         while (it.hasNext()) {
    555             Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
    556             ArrayList<Range> ranges = new ArrayList<Range>(1);
    557             ranges.add(new Range(0, text.length(), entry.getValue()));
    558             attributeMap.put((AttributedCharacterIterator.Attribute) entry
    559                     .getKey(), ranges);
    560         }
    561     }
    562 
    563     /**
    564      * Applies a given attribute to this string.
    565      *
    566      * @param attribute
    567      *            the attribute that will be applied to this string.
    568      * @param value
    569      *            the value of the attribute that will be applied to this
    570      *            string.
    571      * @throws IllegalArgumentException
    572      *             if the length of this attributed string is 0.
    573      * @throws NullPointerException
    574      *             if {@code attribute} is {@code null}.
    575      */
    576     public void addAttribute(AttributedCharacterIterator.Attribute attribute, Object value) {
    577         if (attribute == null) {
    578             throw new NullPointerException();
    579         }
    580         if (text.length() == 0) {
    581             throw new IllegalArgumentException();
    582         }
    583 
    584         List<Range> ranges = attributeMap.get(attribute);
    585         if (ranges == null) {
    586             ranges = new ArrayList<Range>(1);
    587             attributeMap.put(attribute, ranges);
    588         } else {
    589             ranges.clear();
    590         }
    591         ranges.add(new Range(0, text.length(), value));
    592     }
    593 
    594     /**
    595      * Applies a given attribute to the given range of this string.
    596      *
    597      * @param attribute
    598      *            the attribute that will be applied to this string.
    599      * @param value
    600      *            the value of the attribute that will be applied to this
    601      *            string.
    602      * @param start
    603      *            the start of the range where the attribute will be applied.
    604      * @param end
    605      *            the end of the range where the attribute will be applied.
    606      * @throws IllegalArgumentException
    607      *             if {@code start < 0}, {@code end} is greater than the length
    608      *             of this string, or if {@code start >= end}.
    609      * @throws NullPointerException
    610      *             if {@code attribute} is {@code null}.
    611      */
    612     public void addAttribute(AttributedCharacterIterator.Attribute attribute,
    613             Object value, int start, int end) {
    614         if (attribute == null) {
    615             throw new NullPointerException();
    616         }
    617         if (start < 0 || end > text.length() || start >= end) {
    618             throw new IllegalArgumentException();
    619         }
    620 
    621         if (value == null) {
    622             return;
    623         }
    624 
    625         List<Range> ranges = attributeMap.get(attribute);
    626         if (ranges == null) {
    627             ranges = new ArrayList<Range>(1);
    628             ranges.add(new Range(start, end, value));
    629             attributeMap.put(attribute, ranges);
    630             return;
    631         }
    632         ListIterator<Range> it = ranges.listIterator();
    633         while (it.hasNext()) {
    634             Range range = it.next();
    635             if (end <= range.start) {
    636                 it.previous();
    637                 break;
    638             } else if (start < range.end
    639                     || (start == range.end && value.equals(range.value))) {
    640                 Range r1 = null, r3;
    641                 it.remove();
    642                 r1 = new Range(range.start, start, range.value);
    643                 r3 = new Range(end, range.end, range.value);
    644 
    645                 while (end > range.end && it.hasNext()) {
    646                     range = it.next();
    647                     if (end <= range.end) {
    648                         if (end > range.start
    649                                 || (end == range.start && value.equals(range.value))) {
    650                             it.remove();
    651                             r3 = new Range(end, range.end, range.value);
    652                             break;
    653                         }
    654                     } else {
    655                         it.remove();
    656                     }
    657                 }
    658 
    659                 if (value.equals(r1.value)) {
    660                     if (value.equals(r3.value)) {
    661                         it.add(new Range(r1.start < start ? r1.start : start,
    662                                 r3.end > end ? r3.end : end, r1.value));
    663                     } else {
    664                         it.add(new Range(r1.start < start ? r1.start : start,
    665                                 end, r1.value));
    666                         if (r3.start < r3.end) {
    667                             it.add(r3);
    668                         }
    669                     }
    670                 } else {
    671                     if (value.equals(r3.value)) {
    672                         if (r1.start < r1.end) {
    673                             it.add(r1);
    674                         }
    675                         it.add(new Range(start, r3.end > end ? r3.end : end,
    676                                 r3.value));
    677                     } else {
    678                         if (r1.start < r1.end) {
    679                             it.add(r1);
    680                         }
    681                         it.add(new Range(start, end, value));
    682                         if (r3.start < r3.end) {
    683                             it.add(r3);
    684                         }
    685                     }
    686                 }
    687                 return;
    688             }
    689         }
    690         it.add(new Range(start, end, value));
    691     }
    692 
    693     /**
    694      * Applies a given set of attributes to the given range of the string.
    695      *
    696      * @param attributes
    697      *            the set of attributes that will be applied to this string.
    698      * @param start
    699      *            the start of the range where the attribute will be applied.
    700      * @param end
    701      *            the end of the range where the attribute will be applied.
    702      * @throws IllegalArgumentException
    703      *             if {@code start < 0}, {@code end} is greater than the length
    704      *             of this string, or if {@code start >= end}.
    705      */
    706     public void addAttributes(
    707             Map<? extends AttributedCharacterIterator.Attribute, ?> attributes,
    708             int start, int end) {
    709         Iterator<?> it = attributes.entrySet().iterator();
    710         while (it.hasNext()) {
    711             Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
    712             addAttribute(
    713                     (AttributedCharacterIterator.Attribute) entry.getKey(),
    714                     entry.getValue(), start, end);
    715         }
    716     }
    717 
    718     /**
    719      * Returns an {@code AttributedCharacterIterator} that gives access to the
    720      * complete content of this attributed string.
    721      *
    722      * @return the newly created {@code AttributedCharacterIterator}.
    723      */
    724     public AttributedCharacterIterator getIterator() {
    725         return new AttributedIterator(this);
    726     }
    727 
    728     /**
    729      * Returns an {@code AttributedCharacterIterator} that gives access to the
    730      * complete content of this attributed string. Only attributes contained in
    731      * {@code attributes} are available from this iterator if they are defined
    732      * for this text.
    733      *
    734      * @param attributes
    735      *            the array containing attributes that will be in the new
    736      *            iterator if they are defined for this text.
    737      * @return the newly created {@code AttributedCharacterIterator}.
    738      */
    739     public AttributedCharacterIterator getIterator(
    740             AttributedCharacterIterator.Attribute[] attributes) {
    741         return new AttributedIterator(this, attributes, 0, text.length());
    742     }
    743 
    744     /**
    745      * Returns an {@code AttributedCharacterIterator} that gives access to the
    746      * contents of this attributed string starting at index {@code start} up to
    747      * index {@code end}. Only attributes contained in {@code attributes} are
    748      * available from this iterator if they are defined for this text.
    749      *
    750      * @param attributes
    751      *            the array containing attributes that will be in the new
    752      *            iterator if they are defined for this text.
    753      * @param start
    754      *            the start index of the iterator on the underlying text.
    755      * @param end
    756      *            the end index of the iterator on the underlying text.
    757      * @return the newly created {@code AttributedCharacterIterator}.
    758      */
    759     public AttributedCharacterIterator getIterator(
    760             AttributedCharacterIterator.Attribute[] attributes, int start,
    761             int end) {
    762         return new AttributedIterator(this, attributes, start, end);
    763     }
    764 }
    765