mirror of
https://github.com/jimeh/undent.git
synced 2026-02-19 03:56:38 +00:00
Merge pull request #6 from jimeh/performance-improvements
feat(performance): improve core undenting performance by 20-30x
This commit is contained in:
105
undent.go
105
undent.go
@@ -5,15 +5,85 @@ package undent
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var matcher = regexp.MustCompile(`(?m)^([ \t]*)(?:\S)`)
|
||||
const (
|
||||
tab = 9
|
||||
lf = 10
|
||||
spc = 32
|
||||
)
|
||||
|
||||
// Bytes removes leading indentation/white-space from given string and returns
|
||||
// it as a byte slice.
|
||||
func Bytes(s string) []byte {
|
||||
return []byte(String(s))
|
||||
if len(s) == 0 {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
// find line feeds
|
||||
lfs := []int{}
|
||||
|
||||
if s[0] != lf {
|
||||
lfs = append(lfs, -1)
|
||||
}
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == lf {
|
||||
lfs = append(lfs, i)
|
||||
}
|
||||
}
|
||||
|
||||
// find smallest indent relative to each line-feed
|
||||
min := 99999999999
|
||||
count := 0
|
||||
|
||||
for i := 0; i < len(lfs); i++ {
|
||||
offset := lfs[i]
|
||||
end := len(s) - 1
|
||||
if i+1 < len(lfs) {
|
||||
end = lfs[i+1]
|
||||
}
|
||||
|
||||
if offset+1 >= end {
|
||||
continue
|
||||
}
|
||||
|
||||
indent := 0
|
||||
lineSeek:
|
||||
for n := offset + 1; n < end && indent < min; n++ {
|
||||
switch s[n] {
|
||||
case spc, tab:
|
||||
indent++
|
||||
default:
|
||||
break lineSeek
|
||||
}
|
||||
}
|
||||
if indent < min {
|
||||
min = indent
|
||||
}
|
||||
if indent > 0 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
// extract each line without indentation
|
||||
out := make([]byte, 0, len(s)-(min*count))
|
||||
|
||||
for i := 0; i < len(lfs); i++ {
|
||||
offset := lfs[i] + 1
|
||||
end := len(s)
|
||||
if i+1 < len(lfs) {
|
||||
end = lfs[i+1] + 1
|
||||
}
|
||||
|
||||
if offset+min < end {
|
||||
out = append(out, s[offset+min:end]...)
|
||||
} else if offset < end {
|
||||
out = append(out, s[offset:end]...)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Bytesf removes leading indentation/white-space from given format string
|
||||
@@ -25,34 +95,7 @@ func Bytesf(format string, a ...interface{}) []byte {
|
||||
|
||||
// String removes leading indentation/white-space from given string.
|
||||
func String(s string) string {
|
||||
if len(s) > 0 && s[0] == '\n' {
|
||||
s = s[1:]
|
||||
}
|
||||
|
||||
matches := matcher.FindAllString(s, -1)
|
||||
if len(matches) == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
index := 0
|
||||
length := len(matches[0])
|
||||
|
||||
for i, s := range matches[1:] {
|
||||
l := len(s)
|
||||
if l < length {
|
||||
index = i + 1
|
||||
length = l
|
||||
}
|
||||
}
|
||||
|
||||
if length <= 1 {
|
||||
return s
|
||||
}
|
||||
indent := matches[index][0 : length-1]
|
||||
|
||||
return regexp.MustCompile(
|
||||
`(?m)^`+regexp.QuoteMeta(indent),
|
||||
).ReplaceAllLiteralString(s, "")
|
||||
return string(Bytes(s))
|
||||
}
|
||||
|
||||
// Stringf removes leading indentation/white-space from given format string
|
||||
|
||||
269
undent_test.go
269
undent_test.go
@@ -59,6 +59,21 @@ var stringTestCases = []struct {
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line space indented without any leading line-breaks",
|
||||
s: ` {
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
@@ -98,7 +113,22 @@ var stringTestCases = []struct {
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line tab indented with leading line breaks",
|
||||
name: "multi-line tab indented without any leading line-breaks",
|
||||
s: ` {
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line tab indented with leading line-breaks",
|
||||
s: `
|
||||
|
||||
|
||||
@@ -197,6 +227,108 @@ world
|
||||
foo
|
||||
bar`,
|
||||
},
|
||||
{
|
||||
name: "long block of text",
|
||||
s: `
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
|
||||
ornare, tellus vel luctus tristique, ipsum ante varius mauris, non
|
||||
hendrerit tellus urna quis ex. Donec efficitur arcu sed iaculis
|
||||
lobortis. Phasellus facilisis vitae mi quis accumsan. Suspendisse
|
||||
rhoncus viverra odio ultricies rhoncus. Cras laoreet tortor
|
||||
vestibulum pharetra luctus. Vivamus sit amet volutpat elit.
|
||||
Suspendisse feugiat lectus id arcu sollicitudin tincidunt. Duis ut
|
||||
sem auctor orci sodales varius in ac odio. Nullam finibus odio at
|
||||
lacus tristique malesuada.
|
||||
|
||||
Morbi nisl nulla, euismod eu enim in, tincidunt varius turpis. Morbi
|
||||
ullamcorper tortor mi, ut aliquam metus posuere vel. Etiam vel dui
|
||||
at quam placerat sollicitudin. Proin aliquam justo vitae mauris
|
||||
gravida porta. Praesent hendrerit egestas ligula, faucibus tincidunt
|
||||
tortor aliquet at. Ut luctus vehicula arcu eget cursus. Suspendisse
|
||||
eget enim mollis, condimentum lacus eu, viverra nulla. Aenean vel
|
||||
sapien eget enim convallis accumsan. Donec dictum ullamcorper leo
|
||||
placerat sollicitudin. Pellentesque habitant morbi tristique
|
||||
senectus et netus et malesuada fames ac turpis egestas. Vestibulum
|
||||
volutpat mattis est, a feugiat purus feugiat at. Quisque at velit ut
|
||||
mauris convallis sodales a et erat. Mauris condimentum augue sit
|
||||
amet arcu sodales, aliquet ultrices ipsum tempor. Donec scelerisque
|
||||
mi ligula, vel volutpat velit posuere a. Sed faucibus dui pulvinar
|
||||
lorem commodo egestas. In facilisis suscipit lacus non suscipit.
|
||||
|
||||
Nunc dictum est nulla, a rhoncus mi posuere id. Morbi at tempus
|
||||
augue. Quisque ac nibh auctor velit auctor placerat id non eros.
|
||||
Nulla condimentum quam id risus suscipit, ut fermentum mauris
|
||||
lacinia. Vestibulum suscipit rutrum ex, sed vulputate nisi tempus
|
||||
ultricies. Sed id ante pretium, accumsan sapien eget, malesuada
|
||||
quam. Phasellus quis commodo enim. Vivamus in purus ac lorem ornare
|
||||
posuere non eu quam. Sed arcu tortor, gravida quis fringilla nec,
|
||||
ultricies et sem. Pellentesque arcu enim, tempor id nisl at, rhoncus
|
||||
efficitur sem. Ut quis placerat quam. Donec maximus a risus sed
|
||||
posuere. Curabitur pretium a diam non aliquet.
|
||||
|
||||
Class aptent taciti sociosqu ad litora torquent per conubia nostra,
|
||||
per inceptos himenaeos. Morbi volutpat felis leo, vel ultrices orci
|
||||
bibendum ac. Integer eu mattis urna. Donec dictum vehicula
|
||||
fermentum. Pellentesque a rutrum ipsum. Donec ultricies elit purus,
|
||||
eget viverra tellus tristique sed. In hac habitasse platea dictumst.
|
||||
Duis elementum semper elit, sit amet rhoncus lacus dictum ac. Nunc
|
||||
pretium enim ac urna efficitur, eget facilisis enim interdum.
|
||||
|
||||
Vivamus vel lectus lacus. Praesent vestibulum vel ligula eget
|
||||
cursus. Quisque eu dignissim erat. Quisque maximus arcu eu turpis
|
||||
pulvinar egestas. Nam aliquet neque sed tellus finibus mollis.
|
||||
Phasellus consequat nibh nec ornare egestas. Donec at pellentesque
|
||||
lorem.`,
|
||||
want: `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
|
||||
ornare, tellus vel luctus tristique, ipsum ante varius mauris, non
|
||||
hendrerit tellus urna quis ex. Donec efficitur arcu sed iaculis
|
||||
lobortis. Phasellus facilisis vitae mi quis accumsan. Suspendisse
|
||||
rhoncus viverra odio ultricies rhoncus. Cras laoreet tortor
|
||||
vestibulum pharetra luctus. Vivamus sit amet volutpat elit.
|
||||
Suspendisse feugiat lectus id arcu sollicitudin tincidunt. Duis ut
|
||||
sem auctor orci sodales varius in ac odio. Nullam finibus odio at
|
||||
lacus tristique malesuada.
|
||||
|
||||
Morbi nisl nulla, euismod eu enim in, tincidunt varius turpis. Morbi
|
||||
ullamcorper tortor mi, ut aliquam metus posuere vel. Etiam vel dui
|
||||
at quam placerat sollicitudin. Proin aliquam justo vitae mauris
|
||||
gravida porta. Praesent hendrerit egestas ligula, faucibus tincidunt
|
||||
tortor aliquet at. Ut luctus vehicula arcu eget cursus. Suspendisse
|
||||
eget enim mollis, condimentum lacus eu, viverra nulla. Aenean vel
|
||||
sapien eget enim convallis accumsan. Donec dictum ullamcorper leo
|
||||
placerat sollicitudin. Pellentesque habitant morbi tristique
|
||||
senectus et netus et malesuada fames ac turpis egestas. Vestibulum
|
||||
volutpat mattis est, a feugiat purus feugiat at. Quisque at velit ut
|
||||
mauris convallis sodales a et erat. Mauris condimentum augue sit
|
||||
amet arcu sodales, aliquet ultrices ipsum tempor. Donec scelerisque
|
||||
mi ligula, vel volutpat velit posuere a. Sed faucibus dui pulvinar
|
||||
lorem commodo egestas. In facilisis suscipit lacus non suscipit.
|
||||
|
||||
Nunc dictum est nulla, a rhoncus mi posuere id. Morbi at tempus
|
||||
augue. Quisque ac nibh auctor velit auctor placerat id non eros.
|
||||
Nulla condimentum quam id risus suscipit, ut fermentum mauris
|
||||
lacinia. Vestibulum suscipit rutrum ex, sed vulputate nisi tempus
|
||||
ultricies. Sed id ante pretium, accumsan sapien eget, malesuada
|
||||
quam. Phasellus quis commodo enim. Vivamus in purus ac lorem ornare
|
||||
posuere non eu quam. Sed arcu tortor, gravida quis fringilla nec,
|
||||
ultricies et sem. Pellentesque arcu enim, tempor id nisl at, rhoncus
|
||||
efficitur sem. Ut quis placerat quam. Donec maximus a risus sed
|
||||
posuere. Curabitur pretium a diam non aliquet.
|
||||
|
||||
Class aptent taciti sociosqu ad litora torquent per conubia nostra,
|
||||
per inceptos himenaeos. Morbi volutpat felis leo, vel ultrices orci
|
||||
bibendum ac. Integer eu mattis urna. Donec dictum vehicula
|
||||
fermentum. Pellentesque a rutrum ipsum. Donec ultricies elit purus,
|
||||
eget viverra tellus tristique sed. In hac habitasse platea dictumst.
|
||||
Duis elementum semper elit, sit amet rhoncus lacus dictum ac. Nunc
|
||||
pretium enim ac urna efficitur, eget facilisis enim interdum.
|
||||
|
||||
Vivamus vel lectus lacus. Praesent vestibulum vel ligula eget
|
||||
cursus. Quisque eu dignissim erat. Quisque maximus arcu eu turpis
|
||||
pulvinar egestas. Nam aliquet neque sed tellus finibus mollis.
|
||||
Phasellus consequat nibh nec ornare egestas. Donec at pellentesque
|
||||
lorem.`,
|
||||
},
|
||||
}
|
||||
|
||||
var stringfTestCases = []struct {
|
||||
@@ -254,6 +386,22 @@ var stringfTestCases = []struct {
|
||||
"foo": [
|
||||
42
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line space indented without any leading line-breaks",
|
||||
s: ` {
|
||||
"hello": "%s",
|
||||
"foo": [
|
||||
%d
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
42
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
@@ -292,6 +440,22 @@ var stringfTestCases = []struct {
|
||||
"foo": [
|
||||
42
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line tab indented without any leading line-breaks",
|
||||
s: ` {
|
||||
"hello": "%s",
|
||||
"foo": [
|
||||
%d
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
42
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
@@ -400,6 +564,109 @@ world
|
||||
foo
|
||||
42`,
|
||||
},
|
||||
{
|
||||
name: "long block of text",
|
||||
s: `
|
||||
Lorem %s dolor sit amet, consectetur adipiscing elit. Nunc
|
||||
ornare, tellus vel luctus tristique, ipsum ante varius mauris, non
|
||||
hendrerit tellus urna quis ex. %s efficitur arcu sed iaculis
|
||||
lobortis. Phasellus facilisis vitae mi quis accumsan. Suspendisse
|
||||
rhoncus viverra odio ultricies rhoncus. Cras laoreet tortor
|
||||
vestibulum pharetra luctus. Vivamus sit amet volutpat elit.
|
||||
Suspendisse feugiat lectus id arcu sollicitudin tincidunt. Duis ut
|
||||
sem auctor orci sodales varius in ac odio. Nullam finibus odio at
|
||||
lacus tristique malesuada.
|
||||
|
||||
Morbi nisl nulla, euismod eu enim in, tincidunt varius turpis. Morbi
|
||||
ullamcorper tortor mi, ut aliquam metus posuere vel. Etiam vel dui
|
||||
at quam placerat sollicitudin. Proin aliquam justo vitae mauris
|
||||
gravida porta. Praesent hendrerit egestas ligula, faucibus tincidunt
|
||||
tortor aliquet at. Ut luctus vehicula arcu eget cursus. Suspendisse
|
||||
eget enim mollis, condimentum lacus eu, viverra nulla. Aenean vel
|
||||
sapien eget enim convallis accumsan. Donec dictum ullamcorper leo
|
||||
placerat sollicitudin. Pellentesque habitant morbi tristique
|
||||
senectus et netus et malesuada fames ac turpis egestas. Vestibulum
|
||||
volutpat mattis est, a feugiat purus feugiat at. Quisque at velit ut
|
||||
mauris convallis sodales a et erat. Mauris condimentum augue sit
|
||||
amet arcu sodales, aliquet ultrices ipsum tempor. Donec scelerisque
|
||||
mi ligula, vel volutpat velit posuere a. Sed faucibus dui pulvinar
|
||||
lorem commodo egestas. In facilisis suscipit lacus non suscipit.
|
||||
|
||||
Nunc dictum est nulla, a rhoncus mi posuere id. Morbi at tempus
|
||||
augue. Quisque ac nibh auctor velit auctor placerat id non eros.
|
||||
Nulla condimentum quam id risus suscipit, ut fermentum mauris
|
||||
lacinia. Vestibulum suscipit rutrum ex, sed vulputate nisi tempus
|
||||
ultricies. Sed id ante pretium, accumsan sapien eget, malesuada
|
||||
quam. Phasellus quis commodo enim. Vivamus in purus ac lorem ornare
|
||||
posuere non eu quam. Sed arcu tortor, gravida quis fringilla nec,
|
||||
ultricies et sem. Pellentesque arcu enim, tempor id nisl at, rhoncus
|
||||
efficitur sem. Ut quis placerat quam. Donec maximus a risus sed
|
||||
posuere. Curabitur pretium a diam non aliquet.
|
||||
|
||||
Class aptent taciti sociosqu ad litora torquent per conubia nostra,
|
||||
per inceptos himenaeos. Morbi volutpat felis leo, vel ultrices orci
|
||||
bibendum ac. Integer eu mattis urna. Donec dictum vehicula
|
||||
fermentum. Pellentesque a rutrum ipsum. Donec ultricies elit purus,
|
||||
eget viverra tellus tristique sed. In hac habitasse platea dictumst.
|
||||
Duis elementum semper elit, sit amet rhoncus lacus dictum ac. Nunc
|
||||
pretium enim ac urna efficitur, eget facilisis enim interdum.
|
||||
|
||||
Vivamus vel lectus lacus. Praesent vestibulum vel ligula eget
|
||||
cursus. Quisque eu dignissim erat. Quisque maximus arcu eu turpis
|
||||
pulvinar egestas. Nam aliquet neque sed tellus finibus mollis.
|
||||
Phasellus consequat nibh nec ornare egestas. Donec at pellentesque
|
||||
lorem.`,
|
||||
a: []interface{}{"ipsum", "Donec"},
|
||||
want: `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
|
||||
ornare, tellus vel luctus tristique, ipsum ante varius mauris, non
|
||||
hendrerit tellus urna quis ex. Donec efficitur arcu sed iaculis
|
||||
lobortis. Phasellus facilisis vitae mi quis accumsan. Suspendisse
|
||||
rhoncus viverra odio ultricies rhoncus. Cras laoreet tortor
|
||||
vestibulum pharetra luctus. Vivamus sit amet volutpat elit.
|
||||
Suspendisse feugiat lectus id arcu sollicitudin tincidunt. Duis ut
|
||||
sem auctor orci sodales varius in ac odio. Nullam finibus odio at
|
||||
lacus tristique malesuada.
|
||||
|
||||
Morbi nisl nulla, euismod eu enim in, tincidunt varius turpis. Morbi
|
||||
ullamcorper tortor mi, ut aliquam metus posuere vel. Etiam vel dui
|
||||
at quam placerat sollicitudin. Proin aliquam justo vitae mauris
|
||||
gravida porta. Praesent hendrerit egestas ligula, faucibus tincidunt
|
||||
tortor aliquet at. Ut luctus vehicula arcu eget cursus. Suspendisse
|
||||
eget enim mollis, condimentum lacus eu, viverra nulla. Aenean vel
|
||||
sapien eget enim convallis accumsan. Donec dictum ullamcorper leo
|
||||
placerat sollicitudin. Pellentesque habitant morbi tristique
|
||||
senectus et netus et malesuada fames ac turpis egestas. Vestibulum
|
||||
volutpat mattis est, a feugiat purus feugiat at. Quisque at velit ut
|
||||
mauris convallis sodales a et erat. Mauris condimentum augue sit
|
||||
amet arcu sodales, aliquet ultrices ipsum tempor. Donec scelerisque
|
||||
mi ligula, vel volutpat velit posuere a. Sed faucibus dui pulvinar
|
||||
lorem commodo egestas. In facilisis suscipit lacus non suscipit.
|
||||
|
||||
Nunc dictum est nulla, a rhoncus mi posuere id. Morbi at tempus
|
||||
augue. Quisque ac nibh auctor velit auctor placerat id non eros.
|
||||
Nulla condimentum quam id risus suscipit, ut fermentum mauris
|
||||
lacinia. Vestibulum suscipit rutrum ex, sed vulputate nisi tempus
|
||||
ultricies. Sed id ante pretium, accumsan sapien eget, malesuada
|
||||
quam. Phasellus quis commodo enim. Vivamus in purus ac lorem ornare
|
||||
posuere non eu quam. Sed arcu tortor, gravida quis fringilla nec,
|
||||
ultricies et sem. Pellentesque arcu enim, tempor id nisl at, rhoncus
|
||||
efficitur sem. Ut quis placerat quam. Donec maximus a risus sed
|
||||
posuere. Curabitur pretium a diam non aliquet.
|
||||
|
||||
Class aptent taciti sociosqu ad litora torquent per conubia nostra,
|
||||
per inceptos himenaeos. Morbi volutpat felis leo, vel ultrices orci
|
||||
bibendum ac. Integer eu mattis urna. Donec dictum vehicula
|
||||
fermentum. Pellentesque a rutrum ipsum. Donec ultricies elit purus,
|
||||
eget viverra tellus tristique sed. In hac habitasse platea dictumst.
|
||||
Duis elementum semper elit, sit amet rhoncus lacus dictum ac. Nunc
|
||||
pretium enim ac urna efficitur, eget facilisis enim interdum.
|
||||
|
||||
Vivamus vel lectus lacus. Praesent vestibulum vel ligula eget
|
||||
cursus. Quisque eu dignissim erat. Quisque maximus arcu eu turpis
|
||||
pulvinar egestas. Nam aliquet neque sed tellus finibus mollis.
|
||||
Phasellus consequat nibh nec ornare egestas. Donec at pellentesque
|
||||
lorem.`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user