Vim regex to add curly braces every few lines - json

I am creating a json file and have worked out how to append double quotes and such to appropriate lines, but I need to know how to wrap every 2 lines in curly braces.
Ex:
"value": "Bahraini Foreign Ministry"
"tag": "project:bahrain;id:2201",
"value": "Bahraini Foreign Minister"
"tag": "project:bahrain;id:2202",
needs to be:
{
"value": "Bahraini Foreign Ministry"
"tag": "project:bahrain;id:2201",
},
{
"value": "Bahraini Foreign Minister"
"tag": "project:bahrain;id:2202",
},
I have tried with :%norm and :%s and am going around in circles here. Any ideas are appreciated!

dNitro's solution is one way to do it. Here is another way:
qqqqqqO{<esc>jjo},<esc>j#qq#q
This creates a recursive macro, e.g. a macro that calls itself. Since recursive macros run until they hit an error, and calling j on the last line throws an error, this will work for any data size. Explanation:
qqq clear the register 'q'. qq starts recording in register 'q'. O{<esc> inserts a bracket on the line above the current line. jj moves down (to the line with "tag" on it). o},<esc> puts a bracket on the next line after the current one. j#q puts on back on a line with "value", and #q calls the 'q' macro. Since it's empty while you record, this won't actually do anything. However, once you hit q#q, this will stop recording, and then call this recursive macro.
Another alternative is to use the :global command, e.g.
:g/value/normal O{^[jjo},
Note that ^[ is a literal escape character that you must enter by pressing "ctrl-v, ctrl-esc"
This is essentially the same thing, except instead of using a macro, it automatically applies the set of keystrokes after "normal" to every line containing the text "value".
And just for fun, here is one last alternative, a substitute command:
:%s/.*"value".*\n.*,/{\r&\r},,
This replaces two lines where the first line contains the text "value", with the same text enclosed in brackets.

Related

How to change all numbers by a % in Visual Studio Code

Sorry I am still a beginner but slowly getting there. I want to change all the "base-purchase-prices" by a % all at once? I am tearing my hair out trying to work out how to do it. There are 7000 line items so simply saying "get a calculator" is not going to work
{
"tradeable-code": "Scissors_01",
"base-purchase-price": "110",
"base-sell-price": "12",
"delta-price": "-1.0",
"can-be-purchased":"default"
},
{
"tradeable-code": "Scissors_Plastic",
"base-purchase-price": "88",
"base-sell-price": "9",
"delta-price": "-1.0",
"can-be-purchased":"default"
},
You can use the extension Regex Text Generator
select all the base-purchase-price prices
perform a regex find with: (?<="base-purchase-price": ")([^"]*)
press Alt+Enter while focus in Find dialog
Execute command: Generate text based on Regular Expression (regex)
for Match Original Text Regular Expression enter: (.*)
for Generator Regular Expression enter: {{=N[1]*1.05:fixed(2):simplify}}
this increases the prices with 5% (1+0.05) and rounds it to 2 decimal digits
if you like the preview type Enter otherwise Esc
press Esc to leave Multi Cursor Mode
Using this extension: Find and Transform, full disclosure - written by me, it is easy to do math on any values in your file.
For example, make this keybinding, in your keybindings.json file (it could also be made into a setting that will become a command in the Command Palette if you want:
{
"key": "alt+c", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
"find": "(?<=base-purchase-price\":\\s*\")(\\d+)",
"isRegex": true,
"replace": [
"$${",
"return ($1 * 1.05).toFixed(2);",
"}$$"
]
}
The find will capture only the digits you want to change. The replace will run any math (or string) operation you want. Here I simply multiplied the capture group $1 by 1.05 and set it to 2 decimal places.

Is there a way to copy a single line of code but have it incrementally increase a number in said line of code for each paste?

I have a line of code I want to mass-paste into a file.
The line of code is "enchantment.level.x": "string". I want to paste this multiple times into my program, but each time I paste the line, I want x to increase by one.
So if line 2000 is "enchantment.level.1": "I", I would want line 2001 to be "enchantment.level.2": "I" (but I would change "I" to "II" manually).
Is there a way I can achieve this?
Thank you
I don't think there is any way to do what you want on each paste. But if you make all your pastes first then you can #rioV8's or my extension to accomplish the same goal.
The extension is Find and Transform that I wrote. It supports replacing with the match number (or index). Put this keybinding into your keybindings.json:
{
"key": "alt+m",
"command": "findInCurrentFile",
"args": {
"find": "(?<=enchantment\\.level\\.)x", // match the "x"
"replace": "${matchNumber}", // replace with the matchNumber
"isRegex": true
}
}
You could make that into a named setting too if you don't want to run it from the Command Palette.
${matchNumber} starts at 1. ${matchIndex} starts at 0.
You can use the extension Regex Text Generator to generate the new numbers.
Paste the line as often as you like
Select the number on all the lines with Multiple Cursors
use the extension and use (.*) for match regex and {{=i+1}} for generator expression

Snowflake how to escape all special characters in a string of an array of objects before we parse it as JSON?

We are loading data into Snowflake using a JavaScript procedure.
The script will loop over an array of objects to load some data. These objects contain string that may have special characters.
i.e.:
"Description": "This file contain "sensitive" information."
The double quotes on sensitive word will become:
"Description": "This file contain \"sensitive\" information."
Which broke the loading script.
The same issue happened when we used HTML tags within description key:
"Description": "Please use <b>specific fonts</b> to update the file".
This is another example on the Snowflake community site.
Also this post recommended setting FIELD_OPTIONALLY_ENCLOSED_BY equal to the special characters, but I am handling large data set which might have all the special characters.
How can we escape special characters automatically without updating the script and use JavaScript to loop over the whole array to anticipate and replace each special character with something else?
EDIT
I tried using JSON_EXTRACT_PATH_TEXT:
select JSON_EXTRACT_PATH_TEXT(parse_json('{
"description": "Please use \"Custom\" fonts"
}'), 'description');
and got the following error:
Error parsing JSON: missing comma, line 2, pos 33.
I think the escape characters generated by the JS procedure are escaped when passing to SQL functions.
'{"description": "Please use \"Custom\" fonts"}'
becomes
'{"description": "Please use "Custom" fonts"}'
Therefore parsing them as JSON/fetching a field from JSON fails. To avoid error, the JavaScript procedure should generate a double backslash instead of a backslash:
'{"description": "Please use \\"Custom\\" fonts"}'
I do not think there is a way to prevent this error without modifying the JavaScript procedure.
I came across this today, Gokhan is right you need the double backslashes to properly escape the quote.
Here are a couple links that explain it a little more:
https://community.snowflake.com/s/article/Escaping-new-line-character-in-JSON-to-avoid-data-loading-errors
https://community.snowflake.com/s/article/Unable-to-Insert-Data-Containing-Back-Slash-from-Stored-Procedure
For my case I found that I could address this challenge by disabling the escaping and then manually replacing the using replace function.
For your example the replace is not necessary.
select parse_json($${"description": "Please use \"Custom\" fonts"}$$);
select parse_json($${"description": "Please use \"Custom\" fonts"}$$):description;

H2 DB CSVREAD does not translate line breaks

I would like to use H2 database embedded in my application to create an in-memory database, populated by a CSV file. So I have used the CSVREAD function.
All is working well except one pesky problem, which is that it doesn't seem to recognize line breaks. It translates \n literally as the two characters \ and n.
The docs say that the default escape character is quotation mark but if I try to use the quotation mark to escape anything else besides another quotation mark, it simply ends the record there.
Is it possible to put text with line breaks into a CSV file and have H2's CSVREAD interpret it correctly somehow? Thanks!
After much experimentation, I found that literally putting returns into the middle of the text is interpreted correctly.
e.g. if you want a record with multiple lines, try this in your csv:
"column 1", "column 2", "column 3 multi-line
still part of column 3
yet still pat of column 3"

How to add space to both ends of a equal-sign when not in parentheses with specified file types?

Is it possible? For example, When in .py and .lua file, not in () and I type =, st3 will automatically add a space to both ends. such as a assignment statement:
a = 1
But it is disabled if in a () state:
func(a=1)
func(a=1,func(b=1))
You can do this by creating a keybinding on the = key, to insert a space, followed by the = and another space, that will check:
that the syntax at the caret corresponds to Python or Lua
that the text between the beginning of the line and the text caret contains no unbalanced brackets
If the conditions are not met, the keybinding is not used, and = will be inserted without surrounding whitespace as normal. (Assuming other keybindings on the = key, if any, are evaluated and found not to apply.)
Steps
In Sublime Text, open the Preferences menu and select Keybindings - User.
If the document is not empty, move the text caret to after the first [ character at the beginning of the document.
Paste in the following:
{ "keys": ["="], "command": "insert", "args": { "characters": " = " }, "context":
[
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
{ "key": "selector", "operator": "equal", "operand": "source.python, source.lua", "match_all": true },
{ "key": "preceding_text", "operator": "regex_match", "operand": "^(([^()]*+)(\\((?:(?2)|(?3))*\\))?+)(?1)*+$", "match_all": true }
]
},
If the document was previously empty, type a [ at the beginning of the document, and a ] at the end of the document. This is to ensure that it is a valid JSON array.
Save the file.
Press the = key in a Python or Lua document, and see that it will automatically insert spaces around it when not inside unbalanced parens.
Explanation of the regex:
This aspect of Sublime Text uses the PCRE regex flavor provided by the Boost library, which supports recursion, and thus allows us to not have to repeat ourselves to determine whether the brackets are balanced or not.
^ start of the line
( begin capture group 1
([^()]*+) - possessively capture every consecutive non-parenthesis character into capture group 2
( begin capture group 3
\( match a literal ( character
(?:(?2)|(?3))* recursively match the same regex pattern that corresponds to capture group 2 or 3 (i.e. recursive), zero or unlimited times
\) match a literal ) character
) end capture group 3
?+ make the previous group optional but possessive
) end capture group 1
(?1)*+ possessively recursively match the same regex pattern that corresponds to capture group 1, zero or unlimited times
$ end of the text to be matched - in this case, where the text caret is, because the preceding_text context is used.
The overall effect is that is will match where any of the following are true on the line where the text caret is, before the caret position:
no parens are used
non-nested parens are opened and closed
nested parens are all closed
there are no closing parens that don't have a corresponding open paren
Because the regex is being stored in JSON, the \ characters need to be escaped with an extra \, which is why the operand string contains \\( but I only refer to \( in the regex explanation.
Scope Selector
To ensure that the keybinding is only active on Python and lua, the scope selector context is used, with an argument of source.python, source.lua. This selector matches either source.python or source.lua, or indeed both together if such a thing were possible to embed one language in the other.
One way to find what the base scope of a language in Sublime Text is, would be to go to the very beginning of a document set to the relevant syntax, and go to the Tools menu -> Developer -> Show Scope Name. It will even work on an empty file.
Scope selectors are borrowed from TextMate, and more documentation on them can be found here:
TextMate docs
SO answer
Keybinding Documentation
More information about keybindings can be found here: http://docs.sublimetext.info/en/latest/reference/key_bindings.html#structure-of-a-key-binding
I personally find it useful to view the default keybindings for inspiration.