Generalized the Java API to accept CharSequence instead of String, which can be helpful if the input is a temporary StringBuilder. This is possible because almost all functions read characters and convert them to another representation in a new buffer instead of storing the input string immutably.

pull/123/head
Project Nayuki 3 years ago
parent 72037f3047
commit 4c74eea03e

@ -33,17 +33,17 @@ package io.nayuki.qrcodegen;
* if it was less than {@link QrCode#MAX_VERSION}. (This advice does not apply to the other
* factory functions because they search all versions up to {@code QrCode.MAX_VERSION}.)</p></li>
* <li><p>Split the text data into better or optimal segments in order to reduce the number of
* bits required. (See {@link QrSegmentAdvanced#makeSegmentsOptimally(String,QrCode.Ecc,int,int)
* bits required. (See {@link QrSegmentAdvanced#makeSegmentsOptimally(CharSequence,QrCode.Ecc,int,int)
* QrSegmentAdvanced.makeSegmentsOptimally()}.)</p></li>
* <li><p>Change the text or binary data to be shorter.</p></li>
* <li><p>Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).</p></li>
* <li><p>Propagate the error upward to the caller/user.</p></li>
* </ul>
* @see QrCode#encodeText(String, QrCode.Ecc)
* @see QrCode#encodeText(CharSequence, QrCode.Ecc)
* @see QrCode#encodeBinary(byte[], QrCode.Ecc)
* @see QrCode#encodeSegments(java.util.List, QrCode.Ecc)
* @see QrCode#encodeSegments(java.util.List, QrCode.Ecc, int, int, int, boolean)
* @see QrSegmentAdvanced#makeSegmentsOptimally(String, QrCode.Ecc, int, int)
* @see QrSegmentAdvanced#makeSegmentsOptimally(CharSequence, QrCode.Ecc, int, int)
*/
public class DataTooLongException extends IllegalArgumentException {

@ -37,7 +37,7 @@ import java.util.Objects;
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes.</p>
* <p>Ways to create a QR Code object:</p>
* <ul>
* <li><p>High level: Take the payload data and call {@link QrCode#encodeText(String,Ecc)}
* <li><p>High level: Take the payload data and call {@link QrCode#encodeText(CharSequence,Ecc)}
* or {@link QrCode#encodeBinary(byte[],Ecc)}.</p></li>
* <li><p>Mid level: Custom-make the list of {@link QrSegment segments}
* and call {@link QrCode#encodeSegments(List,Ecc)} or
@ -66,7 +66,7 @@ public final class QrCode {
* @throws DataTooLongException if the text fails to fit in the
* largest version QR Code at the ECL, which means it is too long
*/
public static QrCode encodeText(String text, Ecc ecl) {
public static QrCode encodeText(CharSequence text, Ecc ecl) {
Objects.requireNonNull(text);
Objects.requireNonNull(ecl);
List<QrSegment> segs = QrSegment.makeSegments(text);
@ -102,7 +102,7 @@ public final class QrCode {
* of the result may be higher than the ecl argument if it can be done without increasing the version.
* <p>This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)}
* This is a mid-level API; the high-level API is {@link #encodeText(CharSequence,Ecc)}
* and {@link #encodeBinary(byte[],Ecc)}.</p>
* @param segs the segments to encode
* @param ecl the error correction level to use (not {@code null}) (boostable)
@ -125,7 +125,7 @@ public final class QrCode {
* mask, or &#x2212;1 to automatically choose an appropriate mask (which may be slow).
* <p>This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)}
* This is a mid-level API; the high-level API is {@link #encodeText(CharSequence,Ecc)}
* and {@link #encodeBinary(byte[],Ecc)}.</p>
* @param segs the segments to encode
* @param ecl the error correction level to use (not {@code null}) (boostable)

@ -34,7 +34,7 @@ import java.util.regex.Pattern;
* A segment of character/binary/control data in a QR Code symbol.
* Instances of this class are immutable.
* <p>The mid-level way to create a segment is to take the payload data and call a
* static factory function such as {@link QrSegment#makeNumeric(String)}. The low-level
* static factory function such as {@link QrSegment#makeNumeric(CharSequence)}. The low-level
* way to create a segment is to custom-make the bit buffer and call the {@link
* QrSegment#QrSegment(Mode,int,BitBuffer) constructor} with appropriate values.</p>
* <p>This segment class imposes no length restrictions, but QR Codes have restrictions.
@ -72,7 +72,7 @@ public final class QrSegment {
* @throws NullPointerException if the string is {@code null}
* @throws IllegalArgumentException if the string contains non-digit characters
*/
public static QrSegment makeNumeric(String digits) {
public static QrSegment makeNumeric(CharSequence digits) {
Objects.requireNonNull(digits);
if (!isNumeric(digits))
throw new IllegalArgumentException("String contains non-numeric characters");
@ -80,7 +80,7 @@ public final class QrSegment {
BitBuffer bb = new BitBuffer();
for (int i = 0; i < digits.length(); ) { // Consume up to 3 digits per iteration
int n = Math.min(digits.length() - i, 3);
bb.appendBits(Integer.parseInt(digits.substring(i, i + n)), n * 3 + 1);
bb.appendBits(Integer.parseInt(digits.subSequence(i, i + n).toString()), n * 3 + 1);
i += n;
}
return new QrSegment(Mode.NUMERIC, digits.length(), bb);
@ -96,7 +96,7 @@ public final class QrSegment {
* @throws NullPointerException if the string is {@code null}
* @throws IllegalArgumentException if the string contains non-encodable characters
*/
public static QrSegment makeAlphanumeric(String text) {
public static QrSegment makeAlphanumeric(CharSequence text) {
Objects.requireNonNull(text);
if (!isAlphanumeric(text))
throw new IllegalArgumentException("String contains unencodable characters in alphanumeric mode");
@ -121,7 +121,7 @@ public final class QrSegment {
* @return a new mutable list (not {@code null}) of segments (not {@code null}) containing the text
* @throws NullPointerException if the text is {@code null}
*/
public static List<QrSegment> makeSegments(String text) {
public static List<QrSegment> makeSegments(CharSequence text) {
Objects.requireNonNull(text);
// Select the most efficient segment encoding automatically
@ -132,7 +132,7 @@ public final class QrSegment {
else if (isAlphanumeric(text))
result.add(makeAlphanumeric(text));
else
result.add(makeBytes(text.getBytes(StandardCharsets.UTF_8)));
result.add(makeBytes(text.toString().getBytes(StandardCharsets.UTF_8)));
return result;
}
@ -168,9 +168,9 @@ public final class QrSegment {
* @param text the string to test for encodability (not {@code null})
* @return {@code true} iff each character is in the range 0 to 9.
* @throws NullPointerException if the string is {@code null}
* @see #makeNumeric(String)
* @see #makeNumeric(CharSequence)
*/
public static boolean isNumeric(String text) {
public static boolean isNumeric(CharSequence text) {
return NUMERIC_REGEX.matcher(text).matches();
}
@ -182,9 +182,9 @@ public final class QrSegment {
* @param text the string to test for encodability (not {@code null})
* @return {@code true} iff each character is in the alphanumeric mode character set
* @throws NullPointerException if the string is {@code null}
* @see #makeAlphanumeric(String)
* @see #makeAlphanumeric(CharSequence)
*/
public static boolean isAlphanumeric(String text) {
public static boolean isAlphanumeric(CharSequence text) {
return ALPHANUMERIC_REGEX.matcher(text).matches();
}

@ -48,7 +48,7 @@ public final class QrSegmentAdvanced {
* in the specified {error correction level, minimum version number, maximum version number}.
* <p>This function can utilize all four text encoding modes: numeric, alphanumeric, byte (UTF-8),
* and kanji. This can be considered as a sophisticated but slower replacement for {@link
* QrSegment#makeSegments(String)}. This requires more input parameters because it searches a
* QrSegment#makeSegments(CharSequence)}. This requires more input parameters because it searches a
* range of versions, like {@link QrCode#encodeSegments(List,QrCode.Ecc,int,int,int,boolean)}.</p>
* @param text the text to be encoded (not {@code null}), which can be any Unicode string
* @param ecl the error correction level to use (not {@code null})
@ -60,7 +60,7 @@ public final class QrSegmentAdvanced {
* @throws IllegalArgumentException if 1 &#x2264; minVersion &#x2264; maxVersion &#x2264; 40 is violated
* @throws DataTooLongException if the text fails to fit in the maxVersion QR Code at the ECL
*/
public static List<QrSegment> makeSegmentsOptimally(String text, QrCode.Ecc ecl, int minVersion, int maxVersion) {
public static List<QrSegment> makeSegmentsOptimally(CharSequence text, QrCode.Ecc ecl, int minVersion, int maxVersion) {
// Check arguments
Objects.requireNonNull(text);
Objects.requireNonNull(ecl);
@ -223,7 +223,7 @@ public final class QrSegmentAdvanced {
// Returns a new array of Unicode code points (effectively
// UTF-32 / UCS-4) representing the given UTF-16 string.
private static int[] toCodePoints(String s) {
private static int[] toCodePoints(CharSequence s) {
int[] result = s.codePoints().toArray();
for (int c : result) {
if (Character.isSurrogate((char)c))
@ -257,9 +257,9 @@ public final class QrSegmentAdvanced {
* @return a segment (not {@code null}) containing the text
* @throws NullPointerException if the string is {@code null}
* @throws IllegalArgumentException if the string contains non-encodable characters
* @see #isEncodableAsKanji(String)
* @see #isEncodableAsKanji(CharSequence)
*/
public static QrSegment makeKanji(String text) {
public static QrSegment makeKanji(CharSequence text) {
Objects.requireNonNull(text);
BitBuffer bb = new BitBuffer();
text.chars().forEachOrdered(c -> {
@ -281,9 +281,9 @@ public final class QrSegmentAdvanced {
* @param text the string to test for encodability (not {@code null})
* @return {@code true} iff each character is in the kanji mode character set
* @throws NullPointerException if the string is {@code null}
* @see #makeKanji(String)
* @see #makeKanji(CharSequence)
*/
public static boolean isEncodableAsKanji(String text) {
public static boolean isEncodableAsKanji(CharSequence text) {
Objects.requireNonNull(text);
return text.chars().allMatch(
c -> isKanji((char)c));

Loading…
Cancel
Save