// ToLower converts all characters in the byte slice from A-Z to a-z.
funcToLower(src[]byte)[]byte{
fori,c:=rangesrc{
ifc>='A'&&c<='Z'{
src[i]=c+('a'-'A')
}
}
returnsrc
}
// EqualFold returns true when s matches case-insensitively the targetLower (which must be lowercase).
funcEqualFold(s,targetLower[]byte)bool{
iflen(s)!=len(targetLower){
returnfalse
}
fori,c:=rangetargetLower{
d:=s[i]
ifd!=c&&(d<'A'||d>'Z'||d+('a'-'A')!=c){
returnfalse
}
}
returntrue
}
// Printable returns a printable string for given rune
funcPrintable(rrune)string{
ifunicode.IsGraphic(r){
returnfmt.Sprintf("%c",r)
}elseifr<128{
returnfmt.Sprintf("0x%02X",r)
}
returnfmt.Sprintf("%U",r)
}
varwhitespaceTable=[256]bool{
// ASCII
false,false,false,false,false,false,false,false,
false,true,true,false,true,true,false,false,// tab, new line, form feed, carriage return
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
true,false,false,false,false,false,false,false,// space
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
// non-ASCII
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
}
// IsWhitespace returns true for space, \n, \r, \t, \f.
funcIsWhitespace(cbyte)bool{
returnwhitespaceTable[c]
}
varnewlineTable=[256]bool{
// ASCII
false,false,false,false,false,false,false,false,
false,false,true,false,false,true,false,false,// new line, carriage return
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
// non-ASCII
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false,
}
// IsNewline returns true for \n, \r.
funcIsNewline(cbyte)bool{
returnnewlineTable[c]
}
// IsAllWhitespace returns true when the entire byte slice consists of space, \n, \r, \t, \f.
funcIsAllWhitespace(b[]byte)bool{
for_,c:=rangeb{
if!IsWhitespace(c){
returnfalse
}
}
returntrue
}
// TrimWhitespace removes any leading and trailing whitespace characters.
funcTrimWhitespace(b[]byte)[]byte{
n:=len(b)
start:=n
fori:=0;i<n;i++{
if!IsWhitespace(b[i]){
start=i
break
}
}
end:=n
fori:=n-1;i>=start;i--{
if!IsWhitespace(b[i]){
end=i+1
break
}
}
returnb[start:end]
}
// ReplaceMultipleWhitespace replaces character series of space, \n, \t, \f, \r into a single space or newline (when the serie contained a \n or \r).
funcReplaceMultipleWhitespace(b[]byte)[]byte{
j,k:=0,0// j is write position, k is start of next text section
fori:=0;i<len(b);i++{
ifIsWhitespace(b[i]){
start:=i
newline:=IsNewline(b[i])
i++
for;i<len(b)&&IsWhitespace(b[i]);i++{
ifIsNewline(b[i]){
newline=true
}
}
ifnewline{
b[start]='\n'
}else{
b[start]=' '
}
if1<i-start{// more than one whitespace
ifj==0{
j=start+1
}else{
j+=copy(b[j:],b[k:start+1])
}
k=i
}
}
}
ifj==0{
returnb
}elseifj==1{// only if starts with whitespace
b[k-1]=b[0]
returnb[k-1:]
}elseifk<len(b){
j+=copy(b[j:],b[k:])
}
returnb[:j]
}
// replaceEntities will replace in b at index i, assuming that b[i] == '&' and that i+3<len(b). The returned int will be the last character of the entity, so that the next iteration can safely do i++ to continue and not miss any entitites.
// ReplaceMultipleWhitespaceAndEntities is a combination of ReplaceMultipleWhitespace and ReplaceEntities. It is faster than executing both sequentially.