001package ezvcard.util; 002 003import java.util.BitSet; 004 005/* 006 Copyright (c) 2012-2023, Michael Angstadt 007 All rights reserved. 008 009 Redistribution and use in source and binary forms, with or without 010 modification, are permitted provided that the following conditions are met: 011 012 1. Redistributions of source code must retain the above copyright notice, this 013 list of conditions and the following disclaimer. 014 2. Redistributions in binary form must reproduce the above copyright notice, 015 this list of conditions and the following disclaimer in the documentation 016 and/or other materials provided with the distribution. 017 018 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 019 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 020 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 021 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 022 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 023 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 024 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 025 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 026 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 027 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 028 029 The views and conclusions contained in the software and documentation are those 030 of the authors and should not be interpreted as representing official policies, 031 either expressed or implied, of the FreeBSD Project. 032 */ 033 034/** 035 * Represents a collection of unique characters. This class is used in place of 036 * regular expressions to improve performance. 037 * @author Michael Angstadt 038 */ 039public class CharacterBitSet { 040 private final BitSet bitSet = new BitSet(128); 041 private final String characters; 042 043 /** 044 * @param characters the list of characters to check for. Ranges of 045 * characters are represented using a hyphen. Therefore, to include a raw 046 * hyphen in the character list, it must come at the very beginning or very 047 * end of the given string. In this example, "a-f_:-", the following 048 * characters are included in the final character list: lowercase letters a 049 * through f, underscores, colons, and hyphens 050 */ 051 public CharacterBitSet(String characters) { 052 this.characters = characters; 053 for (int i = 0; i < characters.length(); i++) { 054 char c = characters.charAt(i); 055 char next = (i < characters.length() - 2) ? characters.charAt(i + 1) : 0; 056 057 if (next == '-') { 058 char start = c; 059 char end = characters.charAt(i + 2); 060 if (start > end) { 061 //swap them 062 char temp = start; 063 start = end; 064 end = temp; 065 } 066 067 bitSet.set(start, end + 1); 068 i += 2; 069 continue; 070 } 071 072 bitSet.set(c); 073 } 074 } 075 076 /** 077 * Gets the character list that was originally passed into this object. 078 * @return the character list 079 */ 080 public String characters() { 081 return characters; 082 } 083 084 /** 085 * Gets the underlying {@link BitSet} object. 086 * @return the {@link BitSet} object 087 */ 088 public BitSet bitSet() { 089 return bitSet; 090 } 091 092 /** 093 * Determines if the given string contains *only* the characters in this bit 094 * set. 095 * @param string the string 096 * @return true if the string contains only the specified characters, false 097 * if not 098 */ 099 public boolean containsOnly(String string) { 100 return containsOnly(string, 0); 101 } 102 103 /** 104 * Determines if the given string contains *only* the characters in this bit 105 * set. 106 * @param string the string 107 * @param startIndex the index to start at in the string 108 * @return true if the string contains only the specified characters, false 109 * if not 110 */ 111 public boolean containsOnly(String string, int startIndex) { 112 for (int i = startIndex; i < string.length(); i++) { 113 char c = string.charAt(i); 114 if (!bitSet.get(c)) { 115 return false; 116 } 117 } 118 return true; 119 } 120 121 /** 122 * Determines if the given string contains at least one of the characters in 123 * this bit set. 124 * @param string the string 125 * @return true if the string contains at least one of the characters, false 126 * if not 127 */ 128 public boolean containsAny(String string) { 129 return containsAny(string, 0); 130 } 131 132 /** 133 * Determines if the given string contains at least one of the characters in 134 * this bit set. 135 * @param string the string 136 * @param startIndex the index to start at in the string 137 * @return true if the string contains at least one of the characters, false 138 * if not 139 */ 140 public boolean containsAny(String string, int startIndex) { 141 for (int i = startIndex; i < string.length(); i++) { 142 char c = string.charAt(i); 143 if (bitSet.get(c)) { 144 return true; 145 } 146 } 147 return false; 148 } 149 150 @Override 151 public int hashCode() { 152 return bitSet.hashCode(); 153 } 154 155 @Override 156 public boolean equals(Object obj) { 157 if (this == obj) return true; 158 if (obj == null) return false; 159 if (getClass() != obj.getClass()) return false; 160 CharacterBitSet other = (CharacterBitSet) obj; 161 return bitSet.equals(other.bitSet); 162 } 163 164 @Override 165 public String toString() { 166 return characters; 167 } 168}