001package ezvcard.util; 002 003import java.util.BitSet; 004 005/* 006 Copyright (c) 2012-2026, 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 return string.chars().skip(startIndex).allMatch(bitSet::get); 113 } 114 115 /** 116 * Determines if the given string contains at least one of the characters in 117 * this bit set. 118 * @param string the string 119 * @return true if the string contains at least one of the characters, false 120 * if not 121 */ 122 public boolean containsAny(String string) { 123 return containsAny(string, 0); 124 } 125 126 /** 127 * Determines if the given string contains at least one of the characters in 128 * this bit set. 129 * @param string the string 130 * @param startIndex the index to start at in the string 131 * @return true if the string contains at least one of the characters, false 132 * if not 133 */ 134 public boolean containsAny(String string, int startIndex) { 135 return string.chars().skip(startIndex).anyMatch(bitSet::get); 136 } 137 138 @Override 139 public int hashCode() { 140 return bitSet.hashCode(); 141 } 142 143 @Override 144 public boolean equals(Object obj) { 145 if (this == obj) return true; 146 if (obj == null) return false; 147 if (getClass() != obj.getClass()) return false; 148 CharacterBitSet other = (CharacterBitSet) obj; 149 return bitSet.equals(other.bitSet); 150 } 151 152 @Override 153 public String toString() { 154 return characters; 155 } 156}