com.abubusoft.kripton.common.Ascii Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2015, 2016 Francesco Benincasa.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.abubusoft.kripton.common;
import static com.abubusoft.kripton.common.Preconditions.checkArgument;
import static com.abubusoft.kripton.common.Preconditions.checkNotNull;
// TODO: Auto-generated Javadoc
/**
* Static methods pertaining to ASCII characters (those in the range of values
* {@code 0x00} through {@code 0x7F}), and to strings containing such
* characters.
*
* ASCII utilities also exist in other classes of this package:
*
*
* - SupportedCharsets#US_ASCII specifies the {@code Charset} of ASCII characters.
*
- CharMatcher#ASCII matches ASCII characters and provides text processing methods
* which operate only on the ASCII characters of a string.
*
*
* @author Craig Berry
* @author Gregory Kick
* @since 7.0
*/
public final class Ascii {
/**
* Instantiates a new ascii.
*/
private Ascii() {}
/* The ASCII control characters, per RFC 20. */
/**
* Null ('\0'): The all-zeros character which may serve to accomplish
* time fill and media fill. Normally used as a C string terminator.
* Although RFC 20 names this as "Null", note that it is distinct
* from the C/C++ "NULL" pointer.
*
* @since 8.0
*/
public static final byte NUL = 0;
/**
* Start of Heading: A communication control character used at
* the beginning of a sequence of characters which constitute a
* machine-sensible address or routing information. Such a sequence is
* referred to as the "heading." An STX character has the effect of
* terminating a heading.
*
* @since 8.0
*/
public static final byte SOH = 1;
/**
* Start of Text: A communication control character which
* precedes a sequence of characters that is to be treated as an entity
* and entirely transmitted through to the ultimate destination. Such a
* sequence is referred to as "text." STX may be used to terminate a
* sequence of characters started by SOH.
*
* @since 8.0
*/
public static final byte STX = 2;
/**
* End of Text: A communication control character used to
* terminate a sequence of characters started with STX and transmitted
* as an entity.
*
* @since 8.0
*/
public static final byte ETX = 3;
/**
* End of Transmission: A communication control character used
* to indicate the conclusion of a transmission, which may have
* contained one or more texts and any associated headings.
*
* @since 8.0
*/
public static final byte EOT = 4;
/**
* Enquiry: A communication control character used in data
* communication systems as a request for a response from a remote
* station. It may be used as a "Who Are You" (WRU) to obtain
* identification, or may be used to obtain station status, or both.
*
* @since 8.0
*/
public static final byte ENQ = 5;
/**
* Acknowledge: A communication control character transmitted
* by a receiver as an affirmative response to a sender.
*
* @since 8.0
*/
public static final byte ACK = 6;
/**
* Bell ('\a'): A character for use when there is a need to call for
* human attention. It may control alarm or attention devices.
*
* @since 8.0
*/
public static final byte BEL = 7;
/**
* Backspace ('\b'): A format effector which controls the movement of
* the printing position one printing space backward on the same
* printing line. (Applicable also to display devices.)
*
* @since 8.0
*/
public static final byte BS = 8;
/**
* Horizontal Tabulation ('\t'): A format effector which controls the
* movement of the printing position to the next in a series of
* predetermined positions along the printing line. (Applicable also to
* display devices and the skip function on punched cards.)
*
* @since 8.0
*/
public static final byte HT = 9;
/**
* Line Feed ('\n'): A format effector which controls the movement of
* the printing position to the next printing line. (Applicable also to
* display devices.) Where appropriate, this character may have the
* meaning "New Line" (NL), a format effector which controls the
* movement of the printing point to the first printing position on the
* next printing line. Use of this convention requires agreement
* between sender and recipient of data.
*
* @since 8.0
*/
public static final byte LF = 10;
/**
* Alternate name for {@link #LF}. ({@code LF} is preferred.)
*
* @since 8.0
*/
public static final byte NL = 10;
/**
* Vertical Tabulation ('\v'): A format effector which controls the
* movement of the printing position to the next in a series of
* predetermined printing lines. (Applicable also to display devices.)
*
* @since 8.0
*/
public static final byte VT = 11;
/**
* Form Feed ('\f'): A format effector which controls the movement of
* the printing position to the first pre-determined printing line on
* the next form or page. (Applicable also to display devices.)
*
* @since 8.0
*/
public static final byte FF = 12;
/**
* Carriage Return ('\r'): A format effector which controls the
* movement of the printing position to the first printing position on
* the same printing line. (Applicable also to display devices.)
*
* @since 8.0
*/
public static final byte CR = 13;
/**
* Shift Out: A control character indicating that the code
* combinations which follow shall be interpreted as outside of the
* character set of the standard code table until a Shift In character
* is reached.
*
* @since 8.0
*/
public static final byte SO = 14;
/**
* Shift In: A control character indicating that the code
* combinations which follow shall be interpreted according to the
* standard code table.
*
* @since 8.0
*/
public static final byte SI = 15;
/**
* Data Link Escape: A communication control character which
* will change the meaning of a limited number of contiguously following
* characters. It is used exclusively to provide supplementary controls
* in data communication networks.
*
* @since 8.0
*/
public static final byte DLE = 16;
/**
* Device Control 1. Characters for the control
* of ancillary devices associated with data processing or
* telecommunication systems, more especially switching devices "on" or
* "off." (If a single "stop" control is required to interrupt or turn
* off ancillary devices, DC4 is the preferred assignment.)
*
* @since 8.0
*/
public static final byte DC1 = 17; // aka XON
/**
* Transmission On: Although originally defined as DC1, this ASCII
* control character is now better known as the XON code used for software
* flow control in serial communications. The main use is restarting
* the transmission after the communication has been stopped by the XOFF
* control code.
*
* @since 8.0
*/
public static final byte XON = 17; // aka DC1
/**
* Device Control 2. Characters for the control
* of ancillary devices associated with data processing or
* telecommunication systems, more especially switching devices "on" or
* "off." (If a single "stop" control is required to interrupt or turn
* off ancillary devices, DC4 is the preferred assignment.)
*
* @since 8.0
*/
public static final byte DC2 = 18;
/**
* Device Control 3. Characters for the control
* of ancillary devices associated with data processing or
* telecommunication systems, more especially switching devices "on" or
* "off." (If a single "stop" control is required to interrupt or turn
* off ancillary devices, DC4 is the preferred assignment.)
*
* @since 8.0
*/
public static final byte DC3 = 19; // aka XOFF
/**
* Transmission off. See {@link #XON} for explanation.
*
* @since 8.0
*/
public static final byte XOFF = 19; // aka DC3
/**
* Device Control 4. Characters for the control
* of ancillary devices associated with data processing or
* telecommunication systems, more especially switching devices "on" or
* "off." (If a single "stop" control is required to interrupt or turn
* off ancillary devices, DC4 is the preferred assignment.)
*
* @since 8.0
*/
public static final byte DC4 = 20;
/**
* Negative Acknowledge: A communication control character
* transmitted by a receiver as a negative response to the sender.
*
* @since 8.0
*/
public static final byte NAK = 21;
/**
* Synchronous Idle: A communication control character used by
* a synchronous transmission system in the absence of any other
* character to provide a signal from which synchronism may be achieved
* or retained.
*
* @since 8.0
*/
public static final byte SYN = 22;
/**
* End of Transmission Block: A communication control character
* used to indicate the end of a block of data for communication
* purposes. ETB is used for blocking data where the block structure is
* not necessarily related to the processing format.
*
* @since 8.0
*/
public static final byte ETB = 23;
/**
* Cancel: A control character used to indicate that the data
* with which it is sent is in error or is to be disregarded.
*
* @since 8.0
*/
public static final byte CAN = 24;
/**
* End of Medium: A control character associated with the sent
* data which may be used to identify the physical end of the medium, or
* the end of the used, or wanted, portion of information recorded on a
* medium. (The position of this character does not necessarily
* correspond to the physical end of the medium.)
*
* @since 8.0
*/
public static final byte EM = 25;
/**
* Substitute: A character that may be substituted for a
* character which is determined to be invalid or in error.
*
* @since 8.0
*/
public static final byte SUB = 26;
/**
* Escape: A control character intended to provide code
* extension (supplementary characters) in general information
* interchange. The Escape character itself is a prefix affecting the
* interpretation of a limited number of contiguously following
* characters.
*
* @since 8.0
*/
public static final byte ESC = 27;
/**
* File Separator: These four information separators may be
* used within data in optional fashion, except that their hierarchical
* relationship shall be: FS is the most inclusive, then GS, then RS,
* and US is least inclusive. (The content and length of a File, Group,
* Record, or Unit are not specified.)
*
* @since 8.0
*/
public static final byte FS = 28;
/**
* Group Separator: These four information separators may be
* used within data in optional fashion, except that their hierarchical
* relationship shall be: FS is the most inclusive, then GS, then RS,
* and US is least inclusive. (The content and length of a File, Group,
* Record, or Unit are not specified.)
*
* @since 8.0
*/
public static final byte GS = 29;
/**
* Record Separator: These four information separators may be
* used within data in optional fashion, except that their hierarchical
* relationship shall be: FS is the most inclusive, then GS, then RS,
* and US is least inclusive. (The content and length of a File, Group,
* Record, or Unit are not specified.)
*
* @since 8.0
*/
public static final byte RS = 30;
/**
* Unit Separator: These four information separators may be
* used within data in optional fashion, except that their hierarchical
* relationship shall be: FS is the most inclusive, then GS, then RS,
* and US is least inclusive. (The content and length of a File, Group,
* Record, or Unit are not specified.)
*
* @since 8.0
*/
public static final byte US = 31;
/**
* Space: A normally non-printing graphic character used to
* separate words. It is also a format effector which controls the
* movement of the printing position, one printing position forward.
* (Applicable also to display devices.)
*
* @since 8.0
*/
public static final byte SP = 32;
/**
* Alternate name for {@link #SP}.
*
* @since 8.0
*/
public static final byte SPACE = 32;
/**
* Delete: This character is used primarily to "erase" or
* "obliterate" erroneous or unwanted characters in perforated tape.
*
* @since 8.0
*/
public static final byte DEL = 127;
/**
* The minimum value of an ASCII character.
*
* @since 9.0 (was type {@code int} before 12.0)
*/
public static final char MIN = 0;
/**
* The maximum value of an ASCII character.
*
* @since 9.0 (was type {@code int} before 12.0)
*/
public static final char MAX = 127;
/**
* Returns a copy of the input string in which all {@linkplain #isUpperCase(char) uppercase ASCII
* characters} have been converted to lowercase. All other characters are copied without
* modification.
*
* @param string the string
* @return the string
*/
public static String toLowerCase(String string) {
int length = string.length();
for (int i = 0; i < length; i++) {
if (isUpperCase(string.charAt(i))) {
char[] chars = string.toCharArray();
for (; i < length; i++) {
char c = chars[i];
if (isUpperCase(c)) {
chars[i] = (char) (c ^ 0x20);
}
}
return String.valueOf(chars);
}
}
return string;
}
/**
* Returns a copy of the input character sequence in which all {@linkplain #isUpperCase(char)
* uppercase ASCII characters} have been converted to lowercase. All other characters are copied
* without modification.
*
* @param chars the chars
* @return the string
* @since 14.0
*/
public static String toLowerCase(CharSequence chars) {
if (chars instanceof String) {
return toLowerCase((String) chars);
}
int length = chars.length();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
builder.append(toLowerCase(chars.charAt(i)));
}
return builder.toString();
}
/**
* If the argument is an {@linkplain #isUpperCase(char) uppercase ASCII character} returns the
* lowercase equivalent. Otherwise returns the argument.
*
* @param c the c
* @return the char
*/
public static char toLowerCase(char c) {
return isUpperCase(c) ? (char) (c ^ 0x20) : c;
}
/**
* Returns a copy of the input string in which all {@linkplain #isLowerCase(char) lowercase ASCII
* characters} have been converted to uppercase. All other characters are copied without
* modification.
*
* @param string the string
* @return the string
*/
public static String toUpperCase(String string) {
int length = string.length();
for (int i = 0; i < length; i++) {
if (isLowerCase(string.charAt(i))) {
char[] chars = string.toCharArray();
for (; i < length; i++) {
char c = chars[i];
if (isLowerCase(c)) {
chars[i] = (char) (c & 0x5f);
}
}
return String.valueOf(chars);
}
}
return string;
}
/**
* Returns a copy of the input character sequence in which all {@linkplain #isLowerCase(char)
* lowercase ASCII characters} have been converted to uppercase. All other characters are copied
* without modification.
*
* @param chars the chars
* @return the string
* @since 14.0
*/
public static String toUpperCase(CharSequence chars) {
if (chars instanceof String) {
return toUpperCase((String) chars);
}
int length = chars.length();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
builder.append(toUpperCase(chars.charAt(i)));
}
return builder.toString();
}
/**
* If the argument is a {@linkplain #isLowerCase(char) lowercase ASCII character} returns the
* uppercase equivalent. Otherwise returns the argument.
*
* @param c the c
* @return the char
*/
public static char toUpperCase(char c) {
return isLowerCase(c) ? (char) (c & 0x5f) : c;
}
/**
* Indicates whether {@code c} is one of the twenty-six lowercase ASCII alphabetic characters
* between {@code 'a'} and {@code 'z'} inclusive. All others (including non-ASCII characters)
* return {@code false}.
*
* @param c the c
* @return true, if is lower case
*/
public static boolean isLowerCase(char c) {
// Note: This was benchmarked against the alternate expression "(char)(c - 'a') < 26" (Nov '13)
// and found to perform at least as well, or better.
return (c >= 'a') && (c <= 'z');
}
/**
* Indicates whether {@code c} is one of the twenty-six uppercase ASCII alphabetic characters
* between {@code 'A'} and {@code 'Z'} inclusive. All others (including non-ASCII characters)
* return {@code false}.
*
* @param c the c
* @return true, if is upper case
*/
public static boolean isUpperCase(char c) {
return (c >= 'A') && (c <= 'Z');
}
/**
* Truncates the given character sequence to the given maximum length. If the length of the
* sequence is greater than {@code maxLength}, the returned string will be exactly
* {@code maxLength} chars in length and will end with the given {@code truncationIndicator}.
* Otherwise, the sequence will be returned as a string with no changes to the content.
*
*
Examples:
*
*
{@code
* Ascii.truncate("foobar", 7, "..."); // returns "foobar"
* Ascii.truncate("foobar", 5, "..."); // returns "fo..." }
*
* Note: This method may work with certain non-ASCII text but is not safe for
* use with arbitrary Unicode text. It is mostly intended for use with text that is known to be
* safe for use with it (such as all-ASCII text) and for simple debugging text. When using this
* method, consider the following:
*
*
* - it may split surrogate pairs
* - it may split characters and combining characters
* - it does not consider word boundaries
* - if truncating for display to users, there are other considerations that must be taken
* into account
* - the appropriate truncation indicator may be locale-dependent
* - it is safe to use non-ASCII characters in the truncation indicator
*
*
* @param seq the seq
* @param maxLength the max length
* @param truncationIndicator the truncation indicator
* @return the string
* @throws IllegalArgumentException if {@code maxLength} is less than the length of
* {@code truncationIndicator}
* @since 16.0
*/
public static String truncate(CharSequence seq, int maxLength, String truncationIndicator) {
checkNotNull(seq);
// length to truncate the sequence to, not including the truncation indicator
int truncationLength = maxLength - truncationIndicator.length();
// in this worst case, this allows a maxLength equal to the length of the truncationIndicator,
// meaning that a string will be truncated to just the truncation indicator itself
checkArgument(truncationLength >= 0,
"maxLength (%s) must be >= length of the truncation indicator (%s)",
maxLength, truncationIndicator.length());
if (seq.length() <= maxLength) {
String string = seq.toString();
if (string.length() <= maxLength) {
return string;
}
// if the length of the toString() result was > maxLength for some reason, truncate that
seq = string;
}
return new StringBuilder(maxLength)
.append(seq, 0, truncationLength)
.append(truncationIndicator)
.toString();
}
/**
* Indicates whether the contents of the given character sequences {@code s1} and {@code s2} are
* equal, ignoring the case of any ASCII alphabetic characters between {@code 'a'} and {@code 'z'}
* or {@code 'A'} and {@code 'Z'} inclusive.
*
* This method is significantly faster than {@link String#equalsIgnoreCase} and should be used
* in preference if at least one of the parameters is known to contain only ASCII characters.
*
*
Note however that this method does not always behave identically to expressions such as:
*
* - {@code string.toUpperCase().equals("UPPER CASE ASCII")}
*
- {@code string.toLowerCase().equals("lower case ascii")}
*
* due to case-folding of some non-ASCII characters (which does not occur in
* {@link String#equalsIgnoreCase}). However in almost all cases that ASCII strings are used,
* the author probably wanted the behavior provided by this method rather than the subtle and
* sometimes surprising behavior of {@code toUpperCase()} and {@code toLowerCase()}.
*
* @param s1 the s 1
* @param s2 the s 2
* @return true, if successful
* @since 16.0
*/
public static boolean equalsIgnoreCase(CharSequence s1, CharSequence s2) {
// Calling length() is the null pointer check (so do it before we can exit early).
int length = s1.length();
if (s1 == s2) {
return true;
}
if (length != s2.length()) {
return false;
}
for (int i = 0; i < length; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 == c2) {
continue;
}
int alphaIndex = getAlphaIndex(c1);
// This was also benchmarked using '&' to avoid branching (but always evaluate the rhs),
// however this showed no obvious improvement.
if (alphaIndex < 26 && alphaIndex == getAlphaIndex(c2)) {
continue;
}
return false;
}
return true;
}
/**
* Returns the non-negative index value of the alpha character {@code c}, regardless of case.
* Ie, 'a'/'A' returns 0 and 'z'/'Z' returns 25. Non-alpha characters return a value of 26 or
* greater.
*
* @param c the c
* @return the alpha index
*/
private static int getAlphaIndex(char c) {
// Fold upper-case ASCII to lower-case and make zero-indexed and unsigned (by casting to char).
return (char) ((c | 0x20) - 'a');
}
}