Repeat match pattern and replace - vim

I'd like to repeat a search and replace as below:
Example:
set_path 1 -start -from [get_obj { A_1[0] B_2[1] .... Z_n[100] }]
replace to
set_path 1 -start -from [get_obj {xyz/A_1[0] xyz/B_2[1] .... xyz/Z_n[100]

hit Esc, and type:
:%s/array/xyz\/array/g

:%s/ \(\u\)/ xyz\/\1/g
\1 means the content matched in the first brackets.
It means replace every space and a uppercase letter to xyz and the uppercase letter.

To make this work with variably named array names, you could do something like this:
s:\v([^[ {]+\[[0-9]+\]):xyz/\1:g
\v turns on "very magic" regular expressions, see :help /magic.
[^[ {]+ ensures the only strings not starting with a bracket, space or curly brace are matched.
\[[0-9]+\] ensures that it "looks" like an array reference.

Related

Tcl - How to replace ? with -

(You'd think this would be easy, but I'm stumped.)
I'm converting an iOS note to a text file, and the note contains "0." and "?" whenever there is a list or bullet.
This was a bulleted list
? item 20
? Item 21
? Item 22
I'm having so much problem replacing the "?"
I don't want to replace a legitimate question mark at the end of a sentence,
but I want to replace the "?" bullets with "-" (preferably anywhere in the line, not just at the beginning)
I tried these searches - no luck
set line "? item 20"
set index_bullet [string first "(\s|\r|\n)(\?)" $line]
set index_bullet [string first "(!\w)(\?)" $line]
set index_bullet [string first ^\? $line]
This works, but it would match any question mark
set index_bullet [string first \? $line]
Does anyone know what I'm doing wrong?
How do I find and replace only question mark bullets with a "-"?
Thank you very much in advance
If you're really wanting to replace a question mark where you've got a regular expression that describes the rule, the regsub command is the right way. (The string first command finds literal substrings only. The string match command uses globbing rules.) In this case, we'll use the -all option so that every instance is replaced:
set line "? item 20"
set replaced [regsub -all {(\s|^)\?(\s)} $line {\1-\2}]
puts "'$line' --> '$replaced'"
# Prints: '? item 20' --> '- item 20'
The main tricks to using regular expressions in Tcl are, as much as possible, to keep REs and their replacements in braces so that the you can use Tcl metacharacters (e.g., backslash or square brackets) without having to fiddle around a lot.
Also, \s by default will match a newline.
It seems likely that a character used to indicate a list item is the first character on the line or the first character after optional whitespace. To match a question mark at the beginning of a line:
string match {\?*} $line
or
string match \\?* $line
The braces or doubled backslash keeps the question mark from being treated as a string match metacharacter.
To find a question mark after optional whitespace:
string match {\?*} [string trimleft $line]
The command returns 1 if it finds a match, and 0 if it doesn't.
To do this with string first, use
if {[string first ? [string trimleft $line]] eq 0} ...
but in that case, keep in mind that the index returned from string first isn't the true location of the question mark. (Use
== instead of eq if you have an older Tcl).
When you have determined that the line contains a question mark in the first non-whitespace position, a simple
set line [regsub {\?} $line -]
will perform a single substitution regardless of where it is.
Documentation:
regsub,
string,
Syntax of Tcl regular expressions
I figured it out.
I did it in two steps:
1) First find the "?"
set index_bullet [string first "\?" $line]
2) Then filter out "?" that is not a bullet
set index_question_mark [string first "\w\?" $line]
I have a solution, but please post if you have a better way of doing this.
Thanks!

Notepad++ remove text between string+bracket and another bracket

So, I've seen that you can remove between two characters and remove between two strings but I haven't been able to find a system that works between a string and a character.
I need to remove the numbers between the two brackets in...
provinces= {
923 6862 9794 9904 11751 11846 11882
}
Keep in mind that these files also contains other brackets which are needed. I've looked around for a solution for this but none seem to work :/
Thanks for the help.
This one will do the job:
Ctrl+H
Find what: \b(provinces\s*=\s*\{)[^}]+(\})
Replace with: $1$2
Replace all
Explanation:
\b : a word boundary
( : start group 1
provinces : literally "provinces"
\s* : 0 or more spaces
= : equal sign
\s* : 0 or more spaces
\{ : an open curly bracket, must be escaped because it has special meaning in regex
) : end group 1
[^}]+ : any character that is not a close curly bracket
(\}) : group 2, a close curly bracket, escaped.
Replacement:
$1$2 : group 1 then group 2

Replace C statement with substitute in vim

I would like to use vim's substitute function (:%s) to search and replace a certain pattern of code. For example if I have code similar to the following:
if(!foo)
I would like to replace it with:
if(foo == NULL)
However, foo is just an example. The variable name can be anything.
This is what I came up with for my vim command:
:%s/if(!.*)/if(.* == NULL)/gc
It searches the statements correctly, but it tries to replace it with ".*" instead of the variable that's there (i.e "foo"). Is there a way to do what I am asking with vim?
If not, is there any other editor/tools I can use to help me with modifications like these?
Thanks in advance!
You need to use capture grouping and backreferencing in order to achieve that:
Pattern String sub. flags
|---------| |------------| |-|
:%s/if(!\(.*\))/if(\1 == NULL)/gc
|---| |--|
| ^
|________|
The matched string in pattern will be exactly repeated in string substitution
:help /\(
\(\) A pattern enclosed by escaped parentheses. /\(/\(\) /\)
E.g., "\(^a\)" matches 'a' at the start of a line.
E51 E54 E55 E872 E873
\1 Matches the same string that was matched by /\1 E65
the first sub-expression in \( and \). {not in Vi}
Example: "\([a-z]\).\1" matches "ata", "ehe", "tot", etc.
\2 Like "\1", but uses second sub-expression, /\2
... /\3
\9 Like "\1", but uses ninth sub-expression. /\9
Note: The numbering of groups is done based on which "\(" comes first
in the pattern (going left to right), NOT based on what is matched
first.
You can use
:%s/if(!\(.*\))/if(\1 == NULL)/gc
By putting .* in \( \) you make numbered captured group, which means that the regex will capture what is in .*
When the replace starts then by using \1 you will print the captured group.
A macro is easy in this case, just do the following:
qa .............. starts macro 'a'
f! .............. jumps to next '!'
x ............... erase that
e ............... jump to the end of word
a ............... starts append mode (insert)
== NULL ........ literal == NULL
<ESC> ........... stop insert mode
q ............... stops macro 'a'
:%norm #a ........ apply marco 'a' in the whole file
:g/^if(!/ norm #a apply macro 'a' in the lines starting with if...
Try the following:
%s/if(!\(.\{-}\))/if(\1 == NULL)/gc
The quantifier .\{-} matches a non-empty word, as few as possible (more strict than .*).
The paranthesis \( and \) are used to divide the searched expression into subexpressions, so that you can use those subgroups in the substitute string.
Finally, \1 allows the user to use the first matched subexpression, in our case it is whatever is caught inside the paranthesis.
I hope this is more clear, more information can be found here. And thanks for the comment that suggests improving the answer.

Tab on Expect String concatenation

I'm kinda a novice on Expect, but I can't get over a problem I have with a logging-monitoring script i'm writing.
I've spent hours googling on why I can't get this to work:
puts $redirect [concat "${time}\t" "${context}\t" "$id\t" "${eventtype}" "${eventstatus}\t" "${eventcontext}" ]
The \t char ( it does not work even with other \chars ) is not showing up. No matter how and where I place it, I've tried different stuff:
puts $redirect [concat "${time}" "\t" "${context}" [...] ]
puts $redirect [concat "${time}\t" "${context}" [...] ]
puts $redirect [concat "${time}" "\t${context}" [...] ]
puts $redirect [concat "${time}" \t "${context}" [...] ]
*where redirect is set redirect [open $logfile a]
*where [...] are other strings I'm concatenating, in the same way.
From http://tcl.tk/man/tcl8.5/TclCmd/Tcl.htm#M10
[5] Argument expansion.
If a word starts with the string “{}” followed by a non-whitespace character, then the leading “{}” is removed and the
rest of the word is parsed and substituted as any other word. After
substitution, the word is parsed as a list (without command or
variable substitutions; backslash substitutions are performed as is
normal for a list and individual internal words may be surrounded by
either braces or double-quote characters), and its words are added to
the command being substituted. For instance, “cmd a {}{b [c]} d
{}{$e f "g h"}” is equivalent to “cmd a b {[c]} d {$e} f "g h"”.
[6] Braces.
If the first character of a word is an open brace (“{”) and rule [5] does not apply, then the word is terminated by the matching close
brace (“}”). Braces nest within the word: for each additional open
brace there must be an additional close brace (however, if an open
brace or close brace within the word is quoted with a backslash then
it is not counted in locating the matching close brace). No
substitutions are performed on the characters between the braces
except for backslash-newline substitutions described below, nor do
semi-colons, newlines, close brackets, or white space receive any
special interpretation. The word will consist of exactly the
characters between the outer braces, not including the braces
themselves.
Ironically, I can get this to work:
puts $redirect [concat "${time}\n" "-\t${context}" [...] ]
If I put a char before the TAB, it works, but I can't use it.
Ex output: 2016-06-01 15:43:12 - macro
Wanted output: 2016-06-01 15:43:12 macro
I've tried on building the string with append but it's like it is eating pieces of string due to max buffer char, is it possible?
Am I missing something?
Thanks in advice.
That is what concat does. It eats whitespace.
From the documentation for concat:
This command joins each of its arguments together with spaces after trimming leading and trailing white-space from each of them. If all the arguments are lists, this has the same effect as concatenating them into a single list. It permits any number of arguments; if no args are supplied, the result is an empty string.
#Etan gave you why it's not working for you.
An alternate way to code that is to use format
puts $redirect [format "%s\t%s\t%s\t%s%s\t%s" $time $context $id $eventtype $eventstatus $eventcontext]

Substitute with an expression and matched pattern

In vim we can substitute with an sub-replace-expression. When the substitute string starts with \= the remainder is interpreted as an expression.
e.g. with text:
bar
bar
and substitute command:
:%s/.*/\='foo \0'/
gives unexpected results:
foo \0
foo \0
instead of:
foo bar
foo bar
The question is: How to evaluate expression with matched pattern in substitute?
When you use a sub-replace-expression, the normal special replacements like & and \1 don't work anymore; everything is interpreted as a Vimscript expression. Fortunately, you can access the captured submatches with submatches(), so it becomes:
:%s/.*/\='foo ' . submatch(0)/
You need :%s/.*/foo \0/
With :%s/.*/\='foo \0'/ you evaluate 'foo \0' but that's a string and it evaluates to itself.
You don't need to evaluate any expression for that, use a regex group and proper escapes
:%s /\(.*\)/foo \1/

Resources