Windows 10 (64 bit), Emacs 25.1
Suppose I has text:
aa11aaa aaaaa "api/method1" bbbbbbb
dddeeee ee "api/method2" ddddddd
ee2222ezzzzzzzzzzzzzzzzzz "api/method1" eeeeeee
aaaaaaa222222222222"api/method3" fffffff
xwwwwxx "api/method4" bbbbbbb
I want to cut all text that contain "api/XXX"
, where XXX is a method name (e.g. method4)
. So the result must be:
aa11aaa aaaaa bbbbbbb
dddeeee ee ddddddd
ee2222ezzzzzzzzzzzzzzzzzz eeeeeee
aaaaaaa222222222222 fffffff
xwwwwxx bbbbbbb
I want to use built-in capabilities of Emacs (without write custom elisp script or Emacs macros).
What you do is search for that string and replace it with an empty string (no characters):
With the cursor where you want to start searching and replacing, do this:
M-x replace-string RET api/XXX RET RET
Or if you need to match a regular-expression, use command replace-regexp instead.
Or if you want to check each search hit individually and tell Emacs whether to replace it, use query-replace (M-%) or query-replace-regexp (C-M-%). You can hit ! when queried to make replacements everywhere from the current position forward.
Use C-h f and enter a command name to get more information about that command. For example, C-h f replace-string tells you:
replace-string is an interactive compiled Lisp function in
replace.el.
(replace-string FROM-STRING TO-STRING &optional DELIMITED START END BACKWARD)
This function is for interactive use only;
in Lisp code use search-forward and replace-match instead.
Replace occurrences of FROM-STRING with TO-STRING.
Preserve case in each match if case-replace and case-fold-search
are non-nil and FROM-STRING has no uppercase letters.
(Preserving case means that if the string matched is all caps, or capitalized,
then its replacement is upcased or capitalized.)
Ignore read-only matches if query-replace-skip-read-only is non-nil,
ignore hidden matches if search-invisible is nil, and ignore more
matches using isearch-filter-predicate.
If replace-lax-whitespace is non-nil, a space or spaces in the string
to be replaced will match a sequence of whitespace chars defined by the
regexp in search-whitespace-regexp.
If replace-char-fold is non-nil, matching uses character folding,
i.e. it ignores diacritics and other differences between equivalent
character strings.
Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
only matches surrounded by word boundaries. A negative prefix arg means
replace backward.
Operates on the region between START and END (if both are nil, from point
to the end of the buffer). Interactively, if Transient Mark mode is
enabled and the mark is active, operates on the contents of the region;
otherwise from point to the end of the buffer’s accessible portion.
Use M-n to pull the last incremental search string to the minibuffer
that reads FROM-STRING.
This function is usually the wrong thing to use in a Lisp program.
What you probably want is a loop like this:
(while (search-forward FROM-STRING nil t)
(replace-match TO-STRING nil t))
which will run faster and will not set the mark or print anything.
(You may need a more complex loop if FROM-STRING can match the null string
and TO-STRING is also null.)
Related
I'm trying to convert multiple instances of Unicode codes to their corresponding characters.
I have some text with this format:
U+00A9
And I want to generate the following next to it:
©
I have tried to select the code in visual mode and use the selection range '<,'> in command mode as input for i_CTRL_V but I don't know how to use special keys on a command.
I haven't found anything useful in the manual with :help command-mode . I could solve this problem using other tools but I want to improve my vim knowledge. Any hint is appreciated.
Edit:
As #m_mlvx has pointed out my goal is to visually select, then run some command that looks up the Unicode and does the substitution. Manually input a substitution like :s/U+00A9/U+00A9 ©/g is not what I'm interested in as it would require manually typing each of the special characters on every substitution.
Any hint is appreciated.
Here are a whole lot of them…
:help i_ctrl-v is about insert mode and ranges matter in command-line mode so :help command-mode is totally irrelevant.
When they work on text, Ex commands only work on lines, not arbitrary text. This makes ranges like '<,'> irrelevant in this case.
After carefully reading :help i_ctrl-v_digit, linked from :help i_ctrl-v, we can conclude that it is supposed to be used:
with a lowercase u,
without the +,
without worrying about the case of the value.
So both of these should be correct:
<C-v>u00a9
<C-v>u00A9
But your input is U+00A9 so, even if you somehow manage to "capture" that U+00A9, you won't be able to use it as-is: it must be sanitized first. I would go with a substitution but, depending on how you want to use that value in the end, there are probably dozens of methods:
substitute('U+00A9', '\(\a\)+\(.*\)', '\L\1\2', '')
Explanation:
\(\a\) captures an alphabetic character.
+ matches a literal +.
\(.*\) captures the rest.
\L lowercases everything that comes after it.
\1\2 reuses the two capture groups above.
From there, we can imagine a substitution-based method. Assuming "And I want to generate the following next to it" means that you want to obtain:
U+00A9©
you could do:
v<motion>
y
:call feedkeys("'>a\<C-v>" . substitute(#", '\(\a\)+\(.*\)', '\L\1\2', '') . "\<Esc>")<CR>
Explanation:
v<motion> visually selects the text covered by <motion>.
y yanks it to the "unnamed register" #".
:help feedkeys() is used as low-level way to send a complex series of characters to Vim's input queue. It allows us to build the macro programatically before executing it.
'> moves the cursor to the end of the visual selection.
a starts insert mode after the cursor.
<C-v> + the output of the substitution inserts the appropriate character.
That snippet begs for being turned into a mapping, though.
In case you would like to just convert unicodes to corresponding characters, you could use such nr2char function:
:%s/U+\(\x\{4\}\)/\=nr2char('0x'.submatch(1))/g
Brief explanation
U+\(\x\{4\}\) - search for a specific pattern (U+ and four hexadecimal characters which are stored in group 1)
\= - substitute with result of expression
'0x'.submatch(1) - append 0x to our group (U+00A9 -> 0x00A9)
In case you would like to have unicode character next to text you need to modify slightly right side (use submatch(0) to get full match and . to append)
In case someone wonders how to compose the substitution command:
'<,'>s/\<[uU]+\(\x\+\)\>/\=submatch(0)..' '..nr2char(str2nr(submatch(1), 16), 1)/g
The regex is:
word start
Letter "U" or "u"
Literal "plus"
One or more hex digits (put into "capture group")
word end
Then substituted by (:h sub-replace-expression) concatenation of:
the whole matched string
single space
character by UTF-8 hex code taken from "capture group"
This is to be executed in Visual/command mode and works over selected line range.
I used this map:
map ,w v/\([^ a-z0-9]\|[^ A-Z0-9]\)*<cr>h
the idea is to select
in the words
mysuperTest
MYSUPER_TEST
mysuper_test
to always select the part that says mysuper
but it doesnt work, not sure why
I would use something like the below:
nnoremap ,w v/\C\%#.\([a-z]\+\<bar>[A-Z]\+\)\zs<cr>h
One point to notice is that in a mapping you need to use <bar> (or escape | with an extra backslash) since otherwise | is recognized as a command separator (see :help map-bar.)
Another one to notice is that you want the match to start at the first character outside the word (so you'll land at the end of the word with the h). The visual selection will expand to the start of the match in a search. I suggest using \zs to set the start of the match explicitly (see :help /\zs.)
Finally, beware of 'ignorecase' or 'smartcase' settings. Use \C to explicitly request a case-sensitive match (see :help /\C.)
I also like the idea of using a stronger anchor for the start of the match, so I'm using \%# to match the current cursor position (see :help /\%#), so you're always sure to match the current word only and not end up wandering through the buffer.
Putting it all together:
\C Case-sensitive search
\%# From cursor position
. Skip first character
\( Either one of:
[a-z]\+ One or more lowercase letters
\| (\<bar>) Or:
[A-Z]\+ One or more uppercase letters
\) End group
\zs Set match position here
I'm skipping the first character under the cursor, since in a CamelCase word, the first character won't match capitalization of the remainder of the word.
I kept your original idea of finding the first character after the word then using h to go back one to the left. But that might be a problem if, for example, the word is at the end of the line.
You can actually match the last character of the word instead with something like [a-z]\+\zs[a-z], which will set the start of the match on the last lowercase character. You can do this for both sides of the group (you can have more than one \zs in your pattern, last wins.) If you structure your match that way, you won't need the final h to go back.
I didn't handle numbers, I'll leave those as an exercise to the reader.
Finally, consider there are quite a few corner cases that can make such a mapping quite tricky to get right. Rather than coming up with your own, why not look at plug-ins which add support for handling CamelCase words that have been battle-tested and will cover use cases a lot more advanced than the simple expression you're using here?
There's the excellent vim-scripts/camelcasemotion by Ingo Karkat which sets up a ,w mapping to move to the start of the next CamelCase word, but also i,w to select the current one. You can use powerful combinations such as v3i,w to visually select the current and next two CamelCase words.
You might also check Tim Pope's tpope/vim-abolish which, among other features, defines a set of cr mappings to do coercion from camelCase to MixedCase, snake_case, UPPER_CASE, etc. (Not directly about selecting them, but still related and you might find it useful.)
How can I find and delete lines which start with the text in?
I use the command C-M-s ^in to find all lines starting with in, but then I don't really know what to do.
M-x flush-lines RET ^in RET
C-h f flush-lines tells you:
flush-lines is an interactive compiled Lisp function in replace.el.
It is bound to menu-bar edit flush-lines.
(flush-lines REGEXP &optional RSTART REND INTERACTIVE)
Delete lines containing matches for REGEXP.
When called from Lisp (and usually when called interactively as
well, see below), applies to the part of the buffer after point.
The line point is in is deleted if and only if it contains a
match for regexp starting after point.
If REGEXP contains upper case characters (excluding those preceded by \)
and search-upper-case is non-nil, the matching is case-sensitive.
Second and third arg RSTART and REND specify the region to operate on.
Lines partially contained in this region are deleted if and only if
they contain a match entirely contained in it.
Interactively, in Transient Mark mode when the mark is active, operate
on the contents of the region. Otherwise, operate from point to the
end of (the accessible portion of) the buffer. When calling this function
from Lisp, you can pretend that it was called interactively by passing
a non-nil INTERACTIVE argument.
If a match is split across lines, all the lines it lies in are deleted.
They are deleted before looking for the next match. Hence, a match
starting on the same line at which another match ended is ignored.
query-replace-regexp "in.*" to "" will be work. you should not input " to the prompt
My plan is to do a pretty standard search replace, replacing all instances of old_string with new_string. The problem is that I only want to do this for an arbitrary number of old_strings following a specific prefix. So for example:
old_string = "a"
new_string = "b"
prefix = "xxxx"
xxxxaaaaaaaa => xxxxbbbbbbbb
xxxxaaapostfix => xxxxbbbpostfix
xxaaaa => xxaaaa
etc. I'm not sure how to do this. I imagine there's some way to say s/xxxxa*/xxxxb{number of a's}/g or something, but I have no idea what it is.
You can definitely do this! I would use the \= register to evaluate some vimscript. From :h s/\=:
Substitute with an expression *sub-replace-expression*
*sub-replace-\=* *s/\=*
When the substitute string starts with "\=" the remainder is interpreted as an
expression.
The special meaning for characters as mentioned at |sub-replace-special| does
not apply except for "<CR>". A <NL> character is used as a line break, you
can get one with a double-quote string: "\n". Prepend a backslash to get a
real <NL> character (which will be a NUL in the file).
Then you can use the repeat and submatch functions to build the right string. For example:
:%s/\(xxxx\)\(a\+\)/\=submatch(1).repeat('b', len(submatch(2)))
I chose to use \+ instead of * because then the pattern will not be found after the substitute command finished (this effects hlsearch and n)
Of course, if you use the \zs and \ze (start/end of match) atoms, you can use less capturing groups, which makes this waaay shorter and clearer.
:%s/xxxx\zsa\+/\=repeat('b', len(submatch(0)))
If you have perl support, you can use
:%perldo s/xxxx\Ka+/"b" x length($&)/ge
xxxx\Ka+ match one or more a only if preceded by xxxx
lookbehind with \K
/ge replace all occurrences in line, e allows to use Perl code in replacement section
"b" x length($&) the string b repeated length($&) number of times
See :h perl for more info
I’m writing a function that edits a certain environment in LaTeX.
The environment basically looks like this:
\begin{quicktikz}
...some stuff...
\end{quicktikz}
or like this:
\begin*{quicktikz}
...some stuff...
\end{quicktikz}
I want to write a function that toggles between the two, when called from within the environment. Since my Vim knowledge ain’t all that, I’m coming up with a simple solution:
Get cursor position with let save_cursor=getpos(".").
Backward search for \begin{quicktikz} using: ?\\begin{quicktikz}\|\\begin\*{quicktikz}.
Search for the { and move left using: normal 0f{h.
Check if the item under cursor equals *:
if it does, do normal x;
if it doesn’t, do normal a*<esc>.
Restore cursor position using call setpos('.',save_cursor).
I know how to do all of this except for step 3. How can I check if the char under the cursor equals to * or not?
If you know a better way of doing this, sharing this would be welcome.
I think the easiest way to retrieve the char under cursor is:
getline(".")[col(".")-1]
Alternatively, you can do it with strpart()
strpart(getline("."), col(".")-1, 1)
The first expression first calls the function getline() passing "." as
argument which means the line where the cursor is positioned will be returned.
Then we use the so called expr8 or expr-[] (see the help) to retrieve a
single character. The number passed comes from another function, col()
which returns the current cursor column. As indexes start in 0, one is subtracted.
You can use it like
if getline(".")[col(".")-1] == '*'
...
Let me propose an alternative implementation of the technique you describe.
:?\\begin\>\zs\*\=?s//\='*'[submatch(0)!='']/|norm!``
The above command consists of two separate commands chained with | (see
:help :bar) in one line. The first one is a substitution (see :help :s)
performed for each line in the specified range,
?\\begin\>\zs\*\=?
According to the range syntax (see :help :range), this range specifies the
only line, that is the previous line where the \\begin\>\zs\*\= pattern
matches the word begin preceded with a backslash and followed by by optional
star character.1 The \zs atom between parts of the pattern
matching \begin and *, sets the start of the match there. So, the match
of the whole pattern is either empty or contains single star character. This
is not necessary for specifying a line in the range, it is useful for reusing
the same pattern later in the :substitute command, where only that star
character or its empty place should be replaced. For details about the
pattern's syntax see :help /\>, :help /\=, :help /\zs.
The substitution itself,
s//\='*'[submatch(0)!='']/
replaces the first occurrence of the last search pattern (which is set by the
backward search in the range) with a string to which the expression
'*'[submatch(0)!=''] evaluates (see :help sub-replace-\=). As the pattern
matches only an empty string or a star character, the subexpression
submatch(0)!='' evaluates to zero if there is no star after \begin, or to
one otherwise. Zero subscript from the string '*' results in a substring
containing the first character of that one-character string. Index one is
equal to the length of the string, therefore subscript results in an empty
string. Thus, when there is a star after \begin, it gets replaced with an
empty string, when a star is not present, zero-width interval just after
\begin is substituted with *.
The second command,
:norm!``
takes advantage of the fact that :substitute command stores the current
cursor position before it actually starts replacement. The `` movement
command jumps back to the position before the latest jump (which occurs in the
aforementioned substitution command) restoring position of the
cursor.2
1 Be careful with search, since in ranges, as usual, it wraps
around the end of file, when the wrapscan option is enabled (it is turned on
by default).
2 Do not confuse `` with the '' command which moves the
cursor to the first non-blank character in the line of the location before the
latest jump.