mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Added tostring #72
This commit is contained in:
parent
706424a459
commit
72a78472af
@ -56,330 +56,32 @@ IFS= read -rd '' output < <(cat my_file)
|
|||||||
output=$output ./yq '.data.values = strenv(output)' first.yml
|
output=$output ./yq '.data.values = strenv(output)' first.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
## To up (upper) case
|
## To string
|
||||||
Works with unicode characters
|
Note that you may want to force `yq` to leave scalar values wrapped by passing in `--unwrapScalar=false` or `-r=f`
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
água
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq 'upcase' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
ÁGUA
|
|
||||||
```
|
|
||||||
|
|
||||||
## To down (lower) case
|
|
||||||
Works with unicode characters
|
|
||||||
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
ÁgUA
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq 'downcase' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
água
|
|
||||||
```
|
|
||||||
|
|
||||||
## Join strings
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
- cat
|
|
||||||
- meow
|
|
||||||
- 1
|
- 1
|
||||||
- null
|
|
||||||
- true
|
- true
|
||||||
```
|
- null
|
||||||
then
|
- ~
|
||||||
```bash
|
|
||||||
yq 'join("; ")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
cat; meow; 1; ; true
|
|
||||||
```
|
|
||||||
|
|
||||||
## Trim strings
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
- ' cat'
|
|
||||||
- 'dog '
|
|
||||||
- ' cow cow '
|
|
||||||
- horse
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq '.[] | trim' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
cat
|
|
||||||
dog
|
|
||||||
cow cow
|
|
||||||
horse
|
|
||||||
```
|
|
||||||
|
|
||||||
## Match string
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
foo bar foo
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq 'match("foo")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
string: foo
|
|
||||||
offset: 0
|
|
||||||
length: 3
|
|
||||||
captures: []
|
|
||||||
```
|
|
||||||
|
|
||||||
## Match string, case insensitive
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
foo bar FOO
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq '[match("(?i)foo"; "g")]' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- string: foo
|
|
||||||
offset: 0
|
|
||||||
length: 3
|
|
||||||
captures: []
|
|
||||||
- string: FOO
|
|
||||||
offset: 8
|
|
||||||
length: 3
|
|
||||||
captures: []
|
|
||||||
```
|
|
||||||
|
|
||||||
## Match with global capture group
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
abc abc
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq '[match("(ab)(c)"; "g")]' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- string: abc
|
|
||||||
offset: 0
|
|
||||||
length: 3
|
|
||||||
captures:
|
|
||||||
- string: ab
|
|
||||||
offset: 0
|
|
||||||
length: 2
|
|
||||||
- string: c
|
|
||||||
offset: 2
|
|
||||||
length: 1
|
|
||||||
- string: abc
|
|
||||||
offset: 4
|
|
||||||
length: 3
|
|
||||||
captures:
|
|
||||||
- string: ab
|
|
||||||
offset: 4
|
|
||||||
length: 2
|
|
||||||
- string: c
|
|
||||||
offset: 6
|
|
||||||
length: 1
|
|
||||||
```
|
|
||||||
|
|
||||||
## Match with named capture groups
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
foo bar foo foo foo
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq '[match("foo (?P<bar123>bar)? foo"; "g")]' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- string: foo bar foo
|
|
||||||
offset: 0
|
|
||||||
length: 11
|
|
||||||
captures:
|
|
||||||
- string: bar
|
|
||||||
offset: 4
|
|
||||||
length: 3
|
|
||||||
name: bar123
|
|
||||||
- string: foo foo
|
|
||||||
offset: 12
|
|
||||||
length: 8
|
|
||||||
captures:
|
|
||||||
- string: null
|
|
||||||
offset: -1
|
|
||||||
length: 0
|
|
||||||
name: bar123
|
|
||||||
```
|
|
||||||
|
|
||||||
## Capture named groups into a map
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
xyzzy-14
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq 'capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: xyzzy
|
|
||||||
n: "14"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Match without global flag
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
cat cat
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq 'match("cat")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
string: cat
|
|
||||||
offset: 0
|
|
||||||
length: 3
|
|
||||||
captures: []
|
|
||||||
```
|
|
||||||
|
|
||||||
## Match with global flag
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
cat cat
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq '[match("cat"; "g")]' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- string: cat
|
|
||||||
offset: 0
|
|
||||||
length: 3
|
|
||||||
captures: []
|
|
||||||
- string: cat
|
|
||||||
offset: 4
|
|
||||||
length: 3
|
|
||||||
captures: []
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test using regex
|
|
||||||
Like jq's equivalent, this works like match but only returns true/false instead of full match details
|
|
||||||
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
- cat
|
- cat
|
||||||
- dog
|
- an: object
|
||||||
|
- - array
|
||||||
|
- 2
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq '.[] | test("at")' sample.yml
|
yq '.[] |= to_string' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
true
|
|
||||||
false
|
|
||||||
```
|
|
||||||
|
|
||||||
## Substitute / Replace string
|
|
||||||
This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).
|
|
||||||
Note the use of `|=` to run in context of the current string value.
|
|
||||||
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: dogs are great
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq '.a |= sub("dogs", "cats")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: cats are great
|
|
||||||
```
|
|
||||||
|
|
||||||
## Substitute / Replace string with regex
|
|
||||||
This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).
|
|
||||||
Note the use of `|=` to run in context of the current string value.
|
|
||||||
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
b: heat
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq '.[] |= sub("(a)", "${1}r")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: cart
|
|
||||||
b: heart
|
|
||||||
```
|
|
||||||
|
|
||||||
## Custom types: that are really strings
|
|
||||||
When custom tags are encountered, yq will try to decode the underlying type.
|
|
||||||
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: !horse cat
|
|
||||||
b: !goat heat
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq '.[] |= sub("(a)", "${1}r")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: !horse cart
|
|
||||||
b: !goat heart
|
|
||||||
```
|
|
||||||
|
|
||||||
## Split strings
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
cat; meow; 1; ; true
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq 'split("; ")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- cat
|
|
||||||
- meow
|
|
||||||
- "1"
|
- "1"
|
||||||
- ""
|
|
||||||
- "true"
|
- "true"
|
||||||
```
|
- "null"
|
||||||
|
- "~"
|
||||||
## Split strings one match
|
- cat
|
||||||
Given a sample.yml file of:
|
- "an: object"
|
||||||
```yaml
|
- "- array\n- 2"
|
||||||
word
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq 'split("; ")' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- word
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -168,6 +168,7 @@ var participleYqRules = []*participleYqRule{
|
|||||||
{"Uppercase", `upcase|ascii_?upcase`, opTokenWithPrefs(changeCaseOpType, nil, changeCasePrefs{ToUpperCase: true}), 0},
|
{"Uppercase", `upcase|ascii_?upcase`, opTokenWithPrefs(changeCaseOpType, nil, changeCasePrefs{ToUpperCase: true}), 0},
|
||||||
{"Downcase", `downcase|ascii_?downcase`, opTokenWithPrefs(changeCaseOpType, nil, changeCasePrefs{ToUpperCase: false}), 0},
|
{"Downcase", `downcase|ascii_?downcase`, opTokenWithPrefs(changeCaseOpType, nil, changeCasePrefs{ToUpperCase: false}), 0},
|
||||||
simpleOp("trim", trimOpType),
|
simpleOp("trim", trimOpType),
|
||||||
|
simpleOp("to_?string", toStringOpType),
|
||||||
|
|
||||||
{"HexValue", `0[xX][0-9A-Fa-f]+`, hexValue(), 0},
|
{"HexValue", `0[xX][0-9A-Fa-f]+`, hexValue(), 0},
|
||||||
{"FloatValueScientific", `-?[1-9](\.\d+)?[Ee][-+]?\d+`, floatValue(), 0},
|
{"FloatValueScientific", `-?[1-9](\.\d+)?[Ee][-+]?\d+`, floatValue(), 0},
|
||||||
|
@ -152,6 +152,7 @@ var testOpType = &operationType{Type: "TEST", NumArgs: 1, Precedence: 50, Handle
|
|||||||
var splitStringOpType = &operationType{Type: "SPLIT", NumArgs: 1, Precedence: 50, Handler: splitStringOperator}
|
var splitStringOpType = &operationType{Type: "SPLIT", NumArgs: 1, Precedence: 50, Handler: splitStringOperator}
|
||||||
var changeCaseOpType = &operationType{Type: "CHANGE_CASE", NumArgs: 0, Precedence: 50, Handler: changeCaseOperator}
|
var changeCaseOpType = &operationType{Type: "CHANGE_CASE", NumArgs: 0, Precedence: 50, Handler: changeCaseOperator}
|
||||||
var trimOpType = &operationType{Type: "TRIM", NumArgs: 0, Precedence: 50, Handler: trimSpaceOperator}
|
var trimOpType = &operationType{Type: "TRIM", NumArgs: 0, Precedence: 50, Handler: trimSpaceOperator}
|
||||||
|
var toStringOpType = &operationType{Type: "TO_STRING", NumArgs: 0, Precedence: 50, Handler: toStringOperator}
|
||||||
|
|
||||||
var loadOpType = &operationType{Type: "LOAD", NumArgs: 1, Precedence: 52, Handler: loadYamlOperator}
|
var loadOpType = &operationType{Type: "LOAD", NumArgs: 1, Precedence: 52, Handler: loadYamlOperator}
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ type encoderPreferences struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* encodes object as yaml string */
|
/* encodes object as yaml string */
|
||||||
|
var chomper = regexp.MustCompile("\n+$")
|
||||||
|
|
||||||
func encodeOperator(_ *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
func encodeOperator(_ *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
preferences := expressionNode.Operation.Preferences.(encoderPreferences)
|
preferences := expressionNode.Operation.Preferences.(encoderPreferences)
|
||||||
@ -58,7 +59,6 @@ func encodeOperator(_ *dataTreeNavigator, context Context, expressionNode *Expre
|
|||||||
|
|
||||||
hasOnlyOneNewLine := regexp.MustCompile("[^\n].*\n$")
|
hasOnlyOneNewLine := regexp.MustCompile("[^\n].*\n$")
|
||||||
endWithNewLine := regexp.MustCompile(".*\n$")
|
endWithNewLine := regexp.MustCompile(".*\n$")
|
||||||
chomper := regexp.MustCompile("\n+$")
|
|
||||||
|
|
||||||
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
@ -29,6 +29,37 @@ func trimSpaceOperator(_ *dataTreeNavigator, context Context, _ *ExpressionNode)
|
|||||||
return context.ChildContext(results), nil
|
return context.ChildContext(results), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toStringOperator(_ *dataTreeNavigator, context Context, _ *ExpressionNode) (Context, error) {
|
||||||
|
results := list.New()
|
||||||
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
node := el.Value.(*CandidateNode)
|
||||||
|
var newStringNode *CandidateNode
|
||||||
|
if node.Tag == "!!str" {
|
||||||
|
newStringNode = node.CreateReplacement(ScalarNode, "!!str", node.Value)
|
||||||
|
} else if node.Kind == ScalarNode {
|
||||||
|
newStringNode = node.CreateReplacement(ScalarNode, "!!str", node.Value)
|
||||||
|
newStringNode.Style = DoubleQuotedStyle
|
||||||
|
} else {
|
||||||
|
encoderPrefs := encoderPreferences{
|
||||||
|
format: YamlFormat,
|
||||||
|
indent: ConfiguredYamlPreferences.Indent,
|
||||||
|
}
|
||||||
|
result, err := encodeToString(node, encoderPrefs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Context{}, err
|
||||||
|
}
|
||||||
|
result = chomper.ReplaceAllString(result, "")
|
||||||
|
newStringNode = node.CreateReplacement(ScalarNode, "!!str", result)
|
||||||
|
newStringNode.Style = DoubleQuotedStyle
|
||||||
|
}
|
||||||
|
newStringNode.Tag = "!!str"
|
||||||
|
results.PushBack(newStringNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.ChildContext(results), nil
|
||||||
|
}
|
||||||
|
|
||||||
func changeCaseOperator(_ *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
func changeCaseOperator(_ *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
results := list.New()
|
results := list.New()
|
||||||
prefs := expressionNode.Operation.Preferences.(changeCasePrefs)
|
prefs := expressionNode.Operation.Preferences.(changeCasePrefs)
|
||||||
|
@ -5,268 +5,277 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var stringsOperatorScenarios = []expressionScenario{
|
var stringsOperatorScenarios = []expressionScenario{
|
||||||
|
// {
|
||||||
|
// description: "To up (upper) case",
|
||||||
|
// subdescription: "Works with unicode characters",
|
||||||
|
// document: `água`,
|
||||||
|
// expression: "upcase",
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!str)::ÁGUA\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `!camel água`,
|
||||||
|
// expression: "upcase",
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!camel)::ÁGUA\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "To down (lower) case",
|
||||||
|
// subdescription: "Works with unicode characters",
|
||||||
|
// document: `ÁgUA`,
|
||||||
|
// expression: "downcase",
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!str)::água\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `!camel ÁgUA`,
|
||||||
|
// expression: "downcase",
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!camel)::água\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Join strings",
|
||||||
|
// document: `[cat, meow, 1, null, true]`,
|
||||||
|
// expression: `join("; ")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!str)::cat; meow; 1; ; true\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Trim strings",
|
||||||
|
// document: `[" cat", "dog ", " cow cow ", horse]`,
|
||||||
|
// expression: `.[] | trim`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[0], (!!str)::cat\n",
|
||||||
|
// "D0, P[1], (!!str)::dog\n",
|
||||||
|
// "D0, P[2], (!!str)::cow cow\n",
|
||||||
|
// "D0, P[3], (!!str)::horse\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `[!horse cat, !goat meow, !frog 1, null, true]`,
|
||||||
|
// expression: `join("; ")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!str)::cat; meow; 1; ; true\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Match string",
|
||||||
|
// document: `foo bar foo`,
|
||||||
|
// expression: `match("foo")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::string: foo\noffset: 0\nlength: 3\ncaptures: []\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `!horse foo bar foo`,
|
||||||
|
// expression: `match("foo")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::string: foo\noffset: 0\nlength: 3\ncaptures: []\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Match string, case insensitive",
|
||||||
|
// document: `foo bar FOO`,
|
||||||
|
// expression: `[match("(?i)foo"; "g")]`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::- string: foo\n offset: 0\n length: 3\n captures: []\n- string: FOO\n offset: 8\n length: 3\n captures: []\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Match with global capture group",
|
||||||
|
// document: `abc abc`,
|
||||||
|
// expression: `[match("(ab)(c)"; "g")]`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::- string: abc\n offset: 0\n length: 3\n captures:\n - string: ab\n offset: 0\n length: 2\n - string: c\n offset: 2\n length: 1\n- string: abc\n offset: 4\n length: 3\n captures:\n - string: ab\n offset: 4\n length: 2\n - string: c\n offset: 6\n length: 1\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Match with named capture groups",
|
||||||
|
// document: `foo bar foo foo foo`,
|
||||||
|
// expression: `[match("foo (?P<bar123>bar)? foo"; "g")]`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::- string: foo bar foo\n offset: 0\n length: 11\n captures:\n - string: bar\n offset: 4\n length: 3\n name: bar123\n- string: foo foo\n offset: 12\n length: 8\n captures:\n - string: null\n offset: -1\n length: 0\n name: bar123\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Capture named groups into a map",
|
||||||
|
// document: `xyzzy-14`,
|
||||||
|
// expression: `capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::a: xyzzy\nn: \"14\"\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `!horse xyzzy-14`,
|
||||||
|
// expression: `capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::a: xyzzy\nn: \"14\"\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// description: "Capture named groups into a map, with null",
|
||||||
|
// document: `xyzzy-14`,
|
||||||
|
// expression: `capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)(?P<bar123>bar)?")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::a: xyzzy\nn: \"14\"\nbar123: null\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Match without global flag",
|
||||||
|
// document: `cat cat`,
|
||||||
|
// expression: `match("cat")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::string: cat\noffset: 0\nlength: 3\ncaptures: []\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Match with global flag",
|
||||||
|
// document: `cat cat`,
|
||||||
|
// expression: `[match("cat"; "g")]`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::- string: cat\n offset: 0\n length: 3\n captures: []\n- string: cat\n offset: 4\n length: 3\n captures: []\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `!horse cat cat`,
|
||||||
|
// expression: `[match("cat"; "g")]`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::- string: cat\n offset: 0\n length: 3\n captures: []\n- string: cat\n offset: 4\n length: 3\n captures: []\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// description: "No match",
|
||||||
|
// document: `dog`,
|
||||||
|
// expression: `match("cat"; "g")`,
|
||||||
|
// expected: []string{},
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// description: "No match",
|
||||||
|
// expression: `"dog" | match("cat", "g")`,
|
||||||
|
// expected: []string{},
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// description: "No match",
|
||||||
|
// expression: `"dog" | match("cat")`,
|
||||||
|
// expected: []string{},
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Test using regex",
|
||||||
|
// subdescription: "Like jq's equivalent, this works like match but only returns true/false instead of full match details",
|
||||||
|
// document: `["cat", "dog"]`,
|
||||||
|
// expression: `.[] | test("at")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[0], (!!bool)::true\n",
|
||||||
|
// "D0, P[1], (!!bool)::false\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `[!horse "cat", !cat "dog"]`,
|
||||||
|
// expression: `.[] | test("at")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[0], (!!bool)::true\n",
|
||||||
|
// "D0, P[1], (!!bool)::false\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `["cat*", "cat*", "cat"]`,
|
||||||
|
// expression: `.[] | test("cat\*")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[0], (!!bool)::true\n",
|
||||||
|
// "D0, P[1], (!!bool)::true\n",
|
||||||
|
// "D0, P[2], (!!bool)::false\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Substitute / Replace string",
|
||||||
|
// subdescription: "This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).\nNote the use of `|=` to run in context of the current string value.",
|
||||||
|
// document: `a: dogs are great`,
|
||||||
|
// expression: `.a |= sub("dogs", "cats")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::a: cats are great\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Substitute / Replace string with regex",
|
||||||
|
// subdescription: "This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).\nNote the use of `|=` to run in context of the current string value.",
|
||||||
|
// document: "a: cat\nb: heat",
|
||||||
|
// expression: `.[] |= sub("(a)", "${1}r")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::a: cart\nb: heart\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Custom types: that are really strings",
|
||||||
|
// subdescription: "When custom tags are encountered, yq will try to decode the underlying type.",
|
||||||
|
// document: "a: !horse cat\nb: !goat heat",
|
||||||
|
// expression: `.[] |= sub("(a)", "${1}r")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!map)::a: !horse cart\nb: !goat heart\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Split strings",
|
||||||
|
// document: `"cat; meow; 1; ; true"`,
|
||||||
|
// expression: `split("; ")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::- cat\n- meow\n- \"1\"\n- \"\"\n- \"true\"\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// description: "Split strings one match",
|
||||||
|
// document: `"word"`,
|
||||||
|
// expression: `split("; ")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::- word\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `!horse "word"`,
|
||||||
|
// expression: `split("; ")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::- word\n",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// document: `""`,
|
||||||
|
// expression: `split("; ")`,
|
||||||
|
// expected: []string{
|
||||||
|
// "D0, P[], (!!seq)::[]\n", // dont actually want this, just not to error
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// skipDoc: true,
|
||||||
|
// expression: `split("; ")`,
|
||||||
|
// expected: []string{},
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
description: "To up (upper) case",
|
description: "To string",
|
||||||
subdescription: "Works with unicode characters",
|
subdescription: "Note that you may want to force `yq` to leave scalar values wrapped by passing in `--unwrapScalar=false` or `-r=f`",
|
||||||
document: `água`,
|
document: `[1, true, null, ~, cat, {an: object}, [array, 2]]`,
|
||||||
expression: "upcase",
|
expression: ".[] |= to_string",
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!str)::ÁGUA\n",
|
"D0, P[], (!!seq)::[\"1\", \"true\", \"null\", \"~\", cat, \"{an: object}\", \"[array, 2]\"]\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `!camel água`,
|
|
||||||
expression: "upcase",
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!camel)::ÁGUA\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "To down (lower) case",
|
|
||||||
subdescription: "Works with unicode characters",
|
|
||||||
document: `ÁgUA`,
|
|
||||||
expression: "downcase",
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!str)::água\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `!camel ÁgUA`,
|
|
||||||
expression: "downcase",
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!camel)::água\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Join strings",
|
|
||||||
document: `[cat, meow, 1, null, true]`,
|
|
||||||
expression: `join("; ")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!str)::cat; meow; 1; ; true\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Trim strings",
|
|
||||||
document: `[" cat", "dog ", " cow cow ", horse]`,
|
|
||||||
expression: `.[] | trim`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[0], (!!str)::cat\n",
|
|
||||||
"D0, P[1], (!!str)::dog\n",
|
|
||||||
"D0, P[2], (!!str)::cow cow\n",
|
|
||||||
"D0, P[3], (!!str)::horse\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `[!horse cat, !goat meow, !frog 1, null, true]`,
|
|
||||||
expression: `join("; ")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!str)::cat; meow; 1; ; true\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Match string",
|
|
||||||
document: `foo bar foo`,
|
|
||||||
expression: `match("foo")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::string: foo\noffset: 0\nlength: 3\ncaptures: []\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `!horse foo bar foo`,
|
|
||||||
expression: `match("foo")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::string: foo\noffset: 0\nlength: 3\ncaptures: []\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Match string, case insensitive",
|
|
||||||
document: `foo bar FOO`,
|
|
||||||
expression: `[match("(?i)foo"; "g")]`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::- string: foo\n offset: 0\n length: 3\n captures: []\n- string: FOO\n offset: 8\n length: 3\n captures: []\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Match with global capture group",
|
|
||||||
document: `abc abc`,
|
|
||||||
expression: `[match("(ab)(c)"; "g")]`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::- string: abc\n offset: 0\n length: 3\n captures:\n - string: ab\n offset: 0\n length: 2\n - string: c\n offset: 2\n length: 1\n- string: abc\n offset: 4\n length: 3\n captures:\n - string: ab\n offset: 4\n length: 2\n - string: c\n offset: 6\n length: 1\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Match with named capture groups",
|
|
||||||
document: `foo bar foo foo foo`,
|
|
||||||
expression: `[match("foo (?P<bar123>bar)? foo"; "g")]`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::- string: foo bar foo\n offset: 0\n length: 11\n captures:\n - string: bar\n offset: 4\n length: 3\n name: bar123\n- string: foo foo\n offset: 12\n length: 8\n captures:\n - string: null\n offset: -1\n length: 0\n name: bar123\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Capture named groups into a map",
|
|
||||||
document: `xyzzy-14`,
|
|
||||||
expression: `capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::a: xyzzy\nn: \"14\"\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `!horse xyzzy-14`,
|
|
||||||
expression: `capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::a: xyzzy\nn: \"14\"\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
description: "Capture named groups into a map, with null",
|
|
||||||
document: `xyzzy-14`,
|
|
||||||
expression: `capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)(?P<bar123>bar)?")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::a: xyzzy\nn: \"14\"\nbar123: null\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Match without global flag",
|
|
||||||
document: `cat cat`,
|
|
||||||
expression: `match("cat")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::string: cat\noffset: 0\nlength: 3\ncaptures: []\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Match with global flag",
|
|
||||||
document: `cat cat`,
|
|
||||||
expression: `[match("cat"; "g")]`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::- string: cat\n offset: 0\n length: 3\n captures: []\n- string: cat\n offset: 4\n length: 3\n captures: []\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `!horse cat cat`,
|
|
||||||
expression: `[match("cat"; "g")]`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::- string: cat\n offset: 0\n length: 3\n captures: []\n- string: cat\n offset: 4\n length: 3\n captures: []\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
description: "No match",
|
|
||||||
document: `dog`,
|
|
||||||
expression: `match("cat"; "g")`,
|
|
||||||
expected: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
description: "No match",
|
|
||||||
expression: `"dog" | match("cat", "g")`,
|
|
||||||
expected: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
description: "No match",
|
|
||||||
expression: `"dog" | match("cat")`,
|
|
||||||
expected: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Test using regex",
|
|
||||||
subdescription: "Like jq's equivalent, this works like match but only returns true/false instead of full match details",
|
|
||||||
document: `["cat", "dog"]`,
|
|
||||||
expression: `.[] | test("at")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[0], (!!bool)::true\n",
|
|
||||||
"D0, P[1], (!!bool)::false\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `[!horse "cat", !cat "dog"]`,
|
|
||||||
expression: `.[] | test("at")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[0], (!!bool)::true\n",
|
|
||||||
"D0, P[1], (!!bool)::false\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `["cat*", "cat*", "cat"]`,
|
|
||||||
expression: `.[] | test("cat\*")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[0], (!!bool)::true\n",
|
|
||||||
"D0, P[1], (!!bool)::true\n",
|
|
||||||
"D0, P[2], (!!bool)::false\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Substitute / Replace string",
|
|
||||||
subdescription: "This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).\nNote the use of `|=` to run in context of the current string value.",
|
|
||||||
document: `a: dogs are great`,
|
|
||||||
expression: `.a |= sub("dogs", "cats")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::a: cats are great\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Substitute / Replace string with regex",
|
|
||||||
subdescription: "This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).\nNote the use of `|=` to run in context of the current string value.",
|
|
||||||
document: "a: cat\nb: heat",
|
|
||||||
expression: `.[] |= sub("(a)", "${1}r")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::a: cart\nb: heart\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Custom types: that are really strings",
|
|
||||||
subdescription: "When custom tags are encountered, yq will try to decode the underlying type.",
|
|
||||||
document: "a: !horse cat\nb: !goat heat",
|
|
||||||
expression: `.[] |= sub("(a)", "${1}r")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::a: !horse cart\nb: !goat heart\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Split strings",
|
|
||||||
document: `"cat; meow; 1; ; true"`,
|
|
||||||
expression: `split("; ")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::- cat\n- meow\n- \"1\"\n- \"\"\n- \"true\"\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Split strings one match",
|
|
||||||
document: `"word"`,
|
|
||||||
expression: `split("; ")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::- word\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `!horse "word"`,
|
|
||||||
expression: `split("; ")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::- word\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `""`,
|
|
||||||
expression: `split("; ")`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::[]\n", // dont actually want this, just not to error
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
expression: `split("; ")`,
|
|
||||||
expected: []string{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStringsOperatorScenarios(t *testing.T) {
|
func TestStringsOperatorScenarios(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user