1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | package Torello.HTML; import Torello.HTML.helper.AttrRegEx; import Torello.Java.StringParse; import java.util.Properties; import java.util.stream.Collectors; import java.util.function.Predicate; import java.util.regex.Matcher; class QuotationMarks { // ******************************************************************************************** // ******************************************************************************************** // Attribute-Value Quotation-Marks - REMOVE // ******************************************************************************************** // ******************************************************************************************** static TagNode removeAVQuotes( final TagNode tn, final Predicate<String> attrNameTest ) { if (tn.isClosing) throw new OpeningTagNodeExpectedException( "Closing TagNode's may not have any attributes, and therefore would not have any " + "quotation-marks to remove." ); // Quick "Optimization" (Skip Out if the length is too short for a RegEx-Match) // // "+6" ==> The following six characters: // '<', '>', At-Least-1-space, At-Least-1-Attr-Char, '=', At-Least-1-Quote if (tn.str.length() <= (tn.tok.length() + 6)) return tn; // Beging the Quotation-Mark Stripping StringBuilder sb = new StringBuilder(); Matcher m = AttrRegEx.KEY_VALUE_REGEX.matcher(tn.str); int pos = 0; while (m.find()) { // Append the "In-Between" Stuff (The "Split" part, rather than the "Match" part) // I have done this enough times to know that this line right here, is the only hard // part to remember when "updating" a TagNode (or any string at all) using a RegEx sb.append(tn.str.substring(pos, m.start(1))); String attrName = m.group(2); if (attrNameTest.test(attrName)) { String attrValue = StringParse.ifQuotesStripQuotes(m.group(3)); if (hasWhiteSpace(attrValue)) throw new QuotesException( "Attempting to remove Quotation-Marks from an Attribute Value that contains " + "Whitespace:\n" + "Attribute-Value: [" + attrValue + "]" ); sb .append(attrName) .append('=') .append(attrValue); } else sb.append(m.group(1)); pos = m.end(); } // Oh, and lastly, that thing about the "hard part" when updating a string using a reg-ex // is: Don't forget about the very last "non-match" which always is checked immediately // after the loop terminates. Add in that very last "non-match" portion. sb.append(tn.str.substring(pos)); return Torello.HTML.EXPORT_PORTAL.newTagNode(tn.tok, sb.toString()); } private static final char[] WHITE_SPACE = { '\t', '\n', '\f', '\r', ' ', 0 }; private static boolean hasWhiteSpace(String attrValue) { for (int i=0; i < attrValue.length(); i++) { final char c = attrValue.charAt(i); for (char ws : WHITE_SPACE) if (c == ws) return true; } return false; } // ******************************************************************************************** // ******************************************************************************************** // Attribute-Value Quotation-Marks - SET // ******************************************************************************************** // ******************************************************************************************** static TagNode setAVQuotes( final TagNode tn, final Predicate<String> attrNameTest, final SD quote ) { if (tn.isClosing) throw new OpeningTagNodeExpectedException( "Closing TagNode's may not have any attributes, and therefore would not have any " + "location in which to insert quotation-marks." ); // Just keep in mind that the Java-Doc for many of the methods in "setAV" states, // explicity that passing 'null' to an 'SD' parameter indicates that the user would like to // have No-Quotes applied to an attribute-value. Here, that option does not exist. java.util.Objects.requireNonNull(quote); // "+6" ==> Same Calculation as in the Method above if (tn.str.length() <= (tn.tok.length() + 6)) return tn; // Beging the Quotation-Mark Stripping StringBuilder sb = new StringBuilder(); Matcher m = AttrRegEx.KEY_VALUE_REGEX.matcher(tn.str); int pos = 0; while (m.find()) { sb.append(tn.str.substring(pos, m.start(1))); String attrName = m.group(2); if (attrNameTest.test(attrName)) { String attrValue = StringParse.ifQuotesStripQuotes(m.group(3)); if (contains(attrValue, quote.quote)) throw new QuotesException( "Attempting to place quotes around an Attribute-Value which already " + "contains at least one copy of the Quote-Character being applied:\n" + "Value: [" + attrValue + "]\n" + "Quote: " + quote.quote + '\n' ); sb .append(attrName) .append('=') .append(quote.quote + attrValue + quote.quote); } else sb.append(m.group(1)); pos = m.end(); } // Oh, and lastly, that thing about the "hard part" when updating a string using a reg-ex // is: Don't forget about the very last "non-match" which always is checked immediately // after the loop terminates. Add in that very last "non-match" portion. sb.append(tn.str.substring(pos)); return Torello.HTML.EXPORT_PORTAL.newTagNode(tn.tok, sb.toString()); } private static boolean contains(String attrValue, char quote) { for (int i=0; i < attrValue.length(); i++) if (attrValue.charAt(i) == quote) return true; return false; } // ******************************************************************************************** // ******************************************************************************************** // Attribute-Value Quotation-Marks - GET // ******************************************************************************************** // ******************************************************************************************** SD getAVQuotes( final TagNode tn, final String attrName ) { String attrValue = null; // AV(attrName, true); if (attrValue == null) throw new RuntimeException // AttributeNotFoundException ("Attribute [" + attrName + "] was not found in TagNode [" + tn.str + "]"); if (attrValue.length() == 0) throw new RuntimeException( // AttributeNotFoundException ( "Attribute [" + attrName + "] found in TagNode [" + tn.str + "] has a " + "String-Length of 0" ); switch (attrValue.charAt(0)) { case '"': return SD.SingleQuotes; case '\'': return SD.DoubleQuotes; default: return null; } } } |