Skip to content

Commit

Permalink
Support trimming and padding modifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
bvisness committed Dec 10, 2023
1 parent 6920514 commit 90501ab
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 42 deletions.
2 changes: 1 addition & 1 deletion stringlib.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func strGsubStr(L *LState, str string, repl string, matches []*pm.MatchData) str
infoList := make([]replaceInfo, 0, len(matches))
for _, match := range matches {
start, end := match.Capture(0), match.Capture(1)
sc := newFlagScanner('%', "", "", repl)
sc := newFlagScanner('%', "", "", "", repl)
for c, eos := sc.Next(); !eos; c, eos = sc.Next() {
if !sc.ChangeFlag {
if sc.HasFlag {
Expand Down
92 changes: 57 additions & 35 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,22 @@ func defaultFormat(v interface{}, f fmt.State, c rune) {
}

type flagScanner struct {
flag byte
start string
end string
buf []byte
str string
Length int
Pos int
HasFlag bool
ChangeFlag bool
flag byte
modifiers []byte
start string
end string
buf []byte
str string
Length int
Pos int
HasFlag bool
ChangeFlag bool
HasModifier bool
Modifier byte
}

func newFlagScanner(flag byte, start, end, str string) *flagScanner {
return &flagScanner{flag, start, end, make([]byte, 0, len(str)), str, len(str), 0, false, false}
func newFlagScanner(flag byte, modifiers, start, end, str string) *flagScanner {
return &flagScanner{flag, []byte(modifiers), start, end, make([]byte, 0, len(str)), str, len(str), 0, false, false, false, 0}
}

func (fs *flagScanner) AppendString(str string) { fs.buf = append(fs.buf, str...) }
Expand All @@ -85,54 +88,65 @@ func (fs *flagScanner) Next() (byte, bool) {
fs.AppendChar(fs.flag)
fs.Pos += 2
return fs.Next()
} else if fs.Pos != fs.Length-1 {
} else if fs.Pos < fs.Length-1 {
if fs.HasFlag {
fs.AppendString(fs.end)
}
fs.AppendString(fs.start)
fs.ChangeFlag = true
fs.HasFlag = true
fs.HasModifier = false
fs.Modifier = 0
if fs.Pos < fs.Length-2 {
for _, modifier := range fs.modifiers {
if fs.str[fs.Pos+1] == modifier {
fs.HasModifier = true
fs.Modifier = modifier
fs.Pos += 1
}
}
}
}
}
}
fs.Pos++
return c, false
}

var cDateFlagToGo = map[byte]string{
var cDateFlagToGo = map[string]string{
// Formatting
'n': "\n",
't': "\t",
"n": "\n",
"t": "\t",

// Year
'Y': "2006", 'y': "06",
"Y": "2006", "y": "06",

// Month
'b': "Jan", 'B': "January", // TODO: %^B, %^b
'm': "01", // TODO: %-m, %_m
"b": "Jan", "B": "January",
"m": "01", "-m": "1",

// Day of the year/month
'j': "002",
'd': "02", 'e': "_2", // TODO: %-d
"j": "002",
"d": "02", "-d": "2", "e": "_2",

// Day of the week
'a': "Mon", 'A': "Monday", // TODO: %^A, %^a
"a": "Mon", "A": "Monday",

// Hour, minute, second
'H': "15",
'I': "03", 'l': "3",
'M': "04",
'S': "05",
"H": "15",
"I": "03", "l": "3",
"M": "04",
"S": "05",

// Other
'c': "02 Jan 06 15:04 MST",
'x': "01/02/06", 'X': "15:04:05",
'D': "01/02/06",
'F': "2006-01-02",
'r': "03:04:05 PM", 'R': "15:04",
'T': "15:04:05",
'p': "PM", 'P': "pm",
'z': "-0700", 'Z': "MST",
"c": "02 Jan 06 15:04 MST",
"x": "01/02/06", "X": "15:04:05",
"D": "01/02/06",
"F": "2006-01-02",
"r": "03:04:05 PM", "R": "15:04",
"T": "15:04:05",
"p": "PM", "P": "pm",
"z": "-0700", "Z": "MST",

// Many other flags are handled in the body of strftime since they cannot
// be represented in Go format strings.
Expand All @@ -142,11 +156,16 @@ var cDateFlagToGo = map[byte]string{
// extensions. This allows for flags like %-d, which provides the day of the
// month without padding (1..31 instead of 01..31).
func strftime(t time.Time, cfmt string) string {
sc := newFlagScanner('%', "", "", cfmt)
sc := newFlagScanner('%', "-", "", "", cfmt)
for c, eos := sc.Next(); !eos; c, eos = sc.Next() {
if !sc.ChangeFlag {
if sc.HasFlag {
if v, ok := cDateFlagToGo[c]; ok {
flag := string(c)
if sc.HasModifier {
flag = string(sc.Modifier) + flag
}

if v, ok := cDateFlagToGo[flag]; ok {
sc.AppendString(t.Format(v))
} else {
switch c {
Expand All @@ -163,6 +182,9 @@ func strftime(t time.Time, cfmt string) string {
sc.AppendString(fmt.Sprint(int(t.Weekday())))
default:
sc.AppendChar('%')
if sc.HasModifier {
sc.AppendChar(sc.Modifier)
}
sc.AppendChar(c)
}
}
Expand Down
15 changes: 9 additions & 6 deletions utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ func TestStrftime(t *testing.T) {

{t1, "%Y %y", "2016 16"},
{t1, "%G %g", "2016 16"},
{t1, "%b %B %m", "Feb February 02"},
{t1, "%b %B", "Feb February"},
{t1, "%m %-m", "02 2"},
{t1, "%V", "5"},
{t1, "%w", "3"},
{t1, "%j", "034"},
{t1, "%d", "03"},
{t1, "%e", " 3"},
{t1, "%d %-d %e", "03 3 3"},
{t1, "%a %A", "Wed Wednesday"},
{t1, "%H %I %l", "13 01 1"},
{t1, "%M", "23"},
Expand All @@ -41,12 +41,12 @@ func TestStrftime(t *testing.T) {

{t2, "%Y %y", "1945 45"},
{t2, "%G %g", "1945 45"},
{t2, "%b %B %m", "Sep September 09"},
{t2, "%b %B", "Sep September"},
{t2, "%m %-m", "09 9"},
{t2, "%V", "36"},
{t2, "%w", "4"},
{t2, "%j", "249"},
{t2, "%d", "06"},
{t2, "%e", " 6"},
{t2, "%d %-d %e", "06 6 6"},
{t2, "%a %A", "Thu Thursday"},
{t2, "%H %I %l", "07 07 7"},
{t2, "%M", "35"},
Expand All @@ -58,6 +58,9 @@ func TestStrftime(t *testing.T) {
{t2, "%R %T %X", "07:35 07:35:04 07:35:04"},
{t2, "%p %P", "AM am"},
{t2, "%z %Z", "-0500 Minus5"},

{t1, "not real flags: %-Q %_J %^^ %-", "not real flags: %-Q %_J %^^ %-"},
{t1, "end in flag: %", "end in flag: %"},
}
for i, c := range cases {
t.Run(fmt.Sprintf("Case %d (\"%s\")", i, c.Fmt), func(t *testing.T) {
Expand Down

0 comments on commit 90501ab

Please sign in to comment.