I have a file which contains text like:
1x
2x
5x
10x
50x
100x
.....
Using Eclipse search and replace with regex, how do I script to have an output like
x1
x2
x5
x10
x50
x100
...
That is to say, search for a regex, break it into fields (\d+x, thus \d+ and 'x' in my case), and reuse the field elements later to resubstitute as 'x'+'\d+'.
I looked at a previous question on same lines, but I want to take that a step further.
Thank you.
Search for
(\d+)x
and replace with
x\1
And enable "Regular expressions". It will put the 'x' in front of the number.
search: (\d+)(.+)
replace with : \2\1
or $2$1 whichever eclipse supports
Related
We have an old, grown project with thousands of php files and need to clean it up.
Throughout the whole project we do have a lot of function calls similar to:
trans('somestring1');
trans("SomeString2");
trans('more_string',$somevar);
trans("anotherstring4",$somevar);
trans($tx_key);
trans($anotherKey,$somevar);
All of those are embedded into the code and represent translation keys. I would like to find a way to extract all "translation keys" in all occurrences.
The PHP project is in VS Code, so a RegEx Search would be helpful to list the results.
Or I could search through the project with any other tool you would recommend
However I would also need to "export" just the strings to a textfile or similar.
The ideal result would be:
somestring1
SomeString2
more_string
anotherstring4
$tx_key
$anotherKey
As a bonus - if someone knows, how I could get the above list including filename where the result has been found - that would be really fantastic!
Any help would be greatly appreciated!
Update:
The RegEx I came up with:
/(trans)+\([^\)]*\)(\.[^\)]*\))?/gim
list the full occurrence - How can I just get the first part of the result (between Single Quotes OR between Double Quotes OR beginning with $)
See here: regexr.com/548d4
Here are some steps to get exactly what you want. Using this you can do a find and replace on your search results!
So you could do sequential regex find/replaces in the right circumstances.
The replace can be just within the search results editor and not affect the underlying files at all - which is what you want.
You can also have the replace action actually edit the underlying files if you wish.
[Hint: This technique can also make doing a find item a / replace with b in files that contain term c much easier to do.]
(1) Open a new search editor: Ctrl+Shift+P
(That command is currently unbound to a keybinding.)
(2) Paste this regex into the Search input box (with the regex option .* selected):
`(.*?)(\btrans\(['"]?)([^,'")]+)(.*)` - a relatively simple regex
regex101 demo
See my other answer for a regex to work with up to 6 entries per line:
(\s*\d+:\s)?((.*?)(\btrans\(['"]?)([^,'")]*)((.*?)(\btrans\(['"]?)([^,'")]*))?((.*?)(\btrans\(['"]?)([^,'")]*))?((.*?)(\btrans\(['"]?)([^,'")]*))?((.*?)(\btrans\(['"]?)([^,'")]*))?((.*?)(\btrans\(['"]?)([^,'")]*))?)(.*)
(3) You will get a list of files with the search results. Now open a Find widget Shift+F in this Search editor.
(4) Put the same regex into that Find input. Regex option selected. Put $3 into the Replace field. This only replaces in this Search editor - not the original files (although that can be done if you want it in some case). Replace All.
If using the 1-6 version regex, replace with:
$1$5 $9 $13 $17 $21 $25
(5) Voila. You can now save this Search Editor as a file.
The first answer works for one desired capture per line as in the original question. But that relatively simple regex won't work if there are two or more per line.
The regex below works for up to 6 entries per line, like
trans('somestring1');
stuff trans("SomeString2"); some content trans("SomeString2a");more stuff [repeat, repeat]
But it doesn't for 7+ - you'll need a regex guru for that.
Here is the process again with a twist of using a snippet in the Search Editor instead of a Find/Replace. Using a snippet allows more control over the formatting of the final result.
(1) Open a new search editor: Ctrl+Shift+P (That command is currently unbound to a keybinding.)
(2) Paste this regex into the Search input box (with the regex option .* selected):
`((.*?)(\btrans\(['"]?)([^,'")]*)((.*?)(\btrans\(['"]?)([^,'")]*))?((.*?)(\btrans\(['"]?)([^,'")]*))?((.*?)(\btrans\(['"]?)([^,'")]*))?((.*?)(\btrans\(['"]?)([^,'")]*))?((.*?)(\btrans\(['"]?)([^,'")]*))?)(.*)`
regex101 demo
(3) You will get a list of files with the search results. Now select all your results individually with Ctrl+Shift+L.
(4) Trigger this keybinding:
{
"key": "alt+i", // whatever keybinding you like
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"snippet": "${TM_SELECTED_TEXT/((.*?)(\\btrans\\([\\'\\\"]?)([^,\\'\\\")]*)((.*?)(\\btrans\\([\\'\\\"]?)([^,\\'\\\")]*))?((.*?)(\\btrans\\([\\'\\\"]?)([^,\\'\\\")]*))?((.*?)(\\btrans\\([\\'\\\"]?)([^,\\'\\\")]*))?((.*?)(\\btrans\\([\\'\\\"]?)([^,\\'\\\")]*))?((.*?)(\\btrans\\([\\'\\\"]?)([^,\\'\\\")]*))?)(.*)/$4${8:+\n }$8${12:+\n }$12${16:+\n }$16${20:+\n }$20${24:+\n }$24/g}"
}
},
That snippet will be applied to each selection in your search result. This part ${8:+\n } is a conditional which adds a newline and some spaces if there is a capture group 8 - which would be a second trans(...) on a line.
Demo: (unfortunately, it doesn't properly show the Ctrl+Shift+L selecting all lines individually or the Alt+i snippet trigger)
Suppose I search on VS Code the terms 'word1 word2'. Then it finds all the occurrences where 'word1' is followed by 'word2'. In reality I want to find all the files where word1 and word2 occur, but they don't have to be consecutive. How can I do it?
Use regex flag and search for (word1[\s\S\n]*word2)|(word2[\s\S\n]*word1)
Made a small extension based on #tonix regex:
https://marketplace.visualstudio.com/items?itemName=usernamehw.search
Here is also a simple way for simple needs - use this as regex
(word1)|(word2)|(word3)
It may not cover some cases, but has been working fine for me, and easy to remember to type it in.
VSCode has an open issue to support multiple searches. You may want to get on there and push them a little.
To apply logical and
(?=.*word1)(?=.*word2)(?=.*word3)
To apply logical or
(word1)|(word2)|(word3)
For you guys,
if you want to search for multiple words (more than 2) at once in a single file and all the words must appear in the file at least once (logical AND), you can use the following regex which leverages lookahead assertions:
^(?=[\s\S\n]*(word1))(?=[\s\S\n]*(word2))(?=[\s\S\n]*(word3))(?=[\s\S\n]*(word4))[\s\S\n]*$
A global search with this pattern will only return all the files that contain word1 AND word2 AND word3 AND word4 in any order (e.g. word4 may appear at the beginning and/or word2 may appear at the end of the file).
I also wrote a little Python CLI helper which creates the regex automatically for you given the patterns you want to AND (though creating the regex by hand is pretty straightforward).
Copy the following code, paste it in a new file and save it somewhere on your machine (I've called it regex_and_lookahead.py). Then make the file executable with chmod +x ./regex_and_lookahead.py (important, I used Python 3.6, the literal prefix f -> f'(?=[\s\S\\n]*({arg}))' won't work in previous versions):
#!/usr/bin/env python
from sys import argv
args = argv[1:]
regex = '^'
for arg in args:
regex += f'(?=[\s\S\\n]*({arg}))'
regex += '[\s\S\\n]*$'
print(regex)
Usage:
./regex_and_lookahead.py word1 word2 word3 word4
Will generate the above regex. You can also use it to generate more complex regexes cause each parameter can have regex characters in it!
As an example:
./regex_and_lookahead.py "pattern with space" "option1|option2" "\bword3\b" "(repeated pattern\.){6}"
Will generate the following regex:
^(?=[\s\S\n]*(pattern with space))(?=[\s\S\n]*(option1|option2))(?=[\s\S\n]*(\bword3\b))(?=[\s\S\n]*((repeated pattern\.){6}))[\s\S\n]*$
Which will match a file if and only if all of the following conditions are true:
There's at least one occurrence of the string pattern with space;
There's at least one occurrence of either option1 or option2;
There's at least one occurrence of the word word3 delimited by word boundary assertions;
There is at least one occurrence of the string repeated pattern. repeated 6 times (i.e.: repeated pattern.repeated pattern.repeated pattern.repeated pattern.repeated pattern.repeated pattern.).
As you can see, the sky is the only limit. Have fun!
This is now supported, you can search for the term then open in editor and use ctrl + f to search the search results thanks #pushkin
This extension: Find and Transform, I am the author, makes it quite easy to do any number of sequential searches across files only using the files from previous search results for future searches.
There is a variable ${resultsFiles} that resolves to those previous search results files and can be used in the "filesToInclude" argument. Here is a sample keybinding
{
"key": "alt+b",
"command": "runInSearchPanel",
"args": {
"find": ["first", "second"],
"delay": 2000, // necessary to allow results to populate
// delay may need to be longer if you are searching a lot of files
"replace": ["", "knuckles"], // optional
"filesToInclude": ["", "${resultsFiles}"],
"filesToExclude": "Users\\Mark\\AppData\\Roaming\\Code\\User\\keybindings.json",
"isRegex": true,
// so that the first search will be triggered and produce results
"triggerSearch": true,
"triggerReplaceAll": [false, true] // optional
}
}
"find": ["first", "second"], : search for first and then search for second
"filesToInclude": ["", "${resultsFiles}"], : clear the filesToInclude on the first search, on second search use the resultFiles from the first search
You can do as many sequential searches as you like
The finds can be regex's and as complex as you wish
The original question asked to do a single search for files containing two separate words in the same file. Below is what I do to search for two (or more) words in the same file by using multiple searches.:
Search Like you normally do
Click on "Open in editor"
Adjust the context line count. (The higher the context count the more you can search for that second term, but the more non relevant searches you bring in)
Hit Cmd + F (or equivalent if not on mac) and search there. In the image below I have narrowed it down to 53 hits. I can manually skip through until I find it.
Need even more Fine tuning?
Same Steps as 1 - 3
Copy the contents to a file. (In the image below I saved it to a file called haystack.ts)
Search there for a third word. (In the image below I have now narrowed it down to 7 searches.)
Try Open new Search Editor command, through command pallete, You can map it to any keybinding you'd like in the Keybindings Editor. I mapped to cmd+shift+i
This is helpful for me!There is one more way, using up/ down arrow key in search editor, moves us across our search history, even this is useful,
It needs a little bent of mind to accept that it is equivalent to having multiple search editors (what IntelliJ etc provides) but without persistence!
I have a file which has contents like so:
size is X1 Identifier is Y1
size is X1 Identifier is Y1
size is X1 Identifier is Y1
I want to re-arrage the file so that I get
Identifier is Y1 size is X1
Identifier is Y1 size is X1
Identifier is Y1 size is X1
How do I do this using vim find & replace? Or any other function in vim?
Use capturing groups and switch both groups
%s/\v(.*) (I.*)/\2 \1
As you say "Or any other function in vim", I'll offer an alternative by recording a macro. Personally I like using macros for things like this because you perform the action you want to do once, which helps you to think through exactly what you want, then just repeat the same thing as many times as you need to.
There's almost certainly a more efficient way than the below, but hopefully this is a fairly straightforward way.
Start with your cursor anywhere in the first line.
qa (start recording a macro in register a - you can substitute the a for any other letter)
0 (move to the start of the line)
Next, perform whatever command you want to use to remove the first part of the line, for example: 3dw - if you need more complex rules to identify the part of the line to move, this is where you would do it.
$ (move to the end of the line)
aSPACEESCp (append a space at the end of the line, then paste the text we deleted previously)
j (move down a line, so we're in the next line when we finish this run of the macro)
q (stop recording)
Once you've completed this, the first line should be in the state that you want it, and your cursor will be in the second line. To repeat the above starting from your current position, just do:
#a (or whatever letter you chose in the first step in place of the a).
I don't use vim that much, but the term you are searching for is "regex capture groups" which exist in nearly every regex implementation.
Capture groups give you the parts of a matched pattern and let you reorganize them to your needs.
Here is a question which might contain your answer:
Similar question
:%s/\(size is \w*\) \(Identifier is \w*\)/\2 \1/g
This works. I assumed that what you marked as X1, Y1 can be any word, hence \w*.
How do I sum or add a certain value to all those numbers? For example my goal is to increase all those numbers inside the "" with 100 but achieving that has been problematic. Basically just somehow sum the current number with +100.
I have the following lines
<devio1="875" devio2="7779" devio3="5635" devio4="154"/>
<devio1="765" devio2="74779" devio3="31535" devio4="544"/>
<devio1="4335" devio2="13" devio3="55635" devio4="1565"/>
By using this regular expression with Notepad++
<devio1="([0-9]+)" devio2="([0-9]+)" devio3="([0-9]+)" devio4="([0-9]+)"/>
I can find all the numbers inside the "" but I cannot find a way to add +100 to all of them. Can this task be achieved with Notepad++ using Regular Expressions?
That's not possible with the sole use of regular expressions in Notepad++. Unfortunately there's no way to perform calculations in the replacement pattern.
So the only way of accomplishing your task in Notepad++ is with the use of the Python Script plugin.
Install Python Script plugin from the Plugin Manager or from the official website.
Then go to Plugins > Python Script > New Script. Choose a filename for your new file (eg add_numbers.py) and copy the code that follows:
def calculate(match):
return 'devio%s="%s"' % (match.group(1), str(int(match.group(2))+100))
editor.rereplace('devio([0-9])="([0-9]+)"', calculate)
Run Plugins > Python Script > Scripts > add_numbers.py and your text will be transformed to:
<devio1="975" devio2="7879" devio3="5735" devio4="254"/>
<devio1="865" devio2="74879" devio3="31635" devio4="644"/>
<devio1="4435" devio2="113" devio3="55735" devio4="1665"/>
I'm not really familiar with notepad++ but for an algorithm, supposing you have a number abcd = a*1000 +b*100 + c*10 + d, then so long as b is in [0,8] you can just replace b by b+1. As for when b = 9 then you need to replace b with 0 and replace a with a+1 (and if a = 9 then you'd replace a by 10).
Noting this, you could then, for three and four digit numbers, say, apply the following regexes:
\([1-9]+\)0\([0-9]{2}\) -> \1 1\2,
\([1-9]+\)1\([0,9]{2}\) -> \1 2\2,
... -> ,
\([1-9]+\)8\([0-9]{2}\) -> \1 9\2,
and so on ... Noting that you also have to consider any a=9, b=9 integers, and larger integers; this suggests some sort of iteration with if statements covering the cases where the coefficients of 10^x (x>=2) are equal to 9. When you start actually coding this (or doing it by hand) you will begin to realize that doing this with a pure regex approach is going to be painful.
Regex doesn't support arithmentic and Notepad++ doesn't support any computation beyond regex, so you're stuck if you're limiting yourself to that tool. There are, of course, many other non-Notepad++ solutions, some of which are discussed in Math operations in regex.
I know this is a long shot, but I have a huge text file and I need to add a given number to other numbers matching some criteria.
Eg.
identifying text 1.1200
identifying text 1.1400
and I'd like to transform this (by adding say 1.15) to
identifying text 2.2700
identifying text 2.2900
Normally I'd do this in Python, but it's on a Windows machine where I can't install too many things. I've got Vim though :)
Here is a simplification and a fix on hobbs' solution:
:%s/identifying text \zs\d\+\(.\d\+\)\=/\=(1.15+str2float(submatch(0)))/
Thanks to \zs, there is no need to recall the leading text. Thanks to str2float() a single addition is done on the whole number (in other words, 1.15 + 2.87 will give the expected result, 4.02, and not 3.102).
Of course this solution requires a recent version of Vim (7.3?)
You can do a capturing regex and then use a vimscript expression as a replacement, something like
:%s/\(identifying text \)\(\d\+\)\.\(\d\+\)/
\=submatch(1) . (submatch(2) + 1) . "." . (submatch(3) + 1500)
(only without the linebreak).
Your number format seems to be a fixed one, so it's easy to convert to int and come back (remove the dot) add 11500 and put the dot back.
:%s/\.//
:%normal11500^A " type C-V then C-a
:%s/....$/.&/
If you don't want to do that on all the lines but only the one which match 'identifying text' replace all the % by 'g/indentifying text/'
For integers you can just use n^A to add n to a number (and n^X to subtract it). I doubt whether that works for fractional numbers though.
Well this might not be a solution for vim but I think awk can help:
cat testscript | LC_ALL=C awk '{printf "%s %s %s %s %.3f\n", $1,$2,$3,$4,$5+1.567 }'
and the test
this is a number 1.56
this is a number 2.56
this is a number 3.56
I needed the LC_ALL=C for the correct conversion of the floating point separator, and maybe there is a more elegant solution for printing the beginning/ rest of the string. And the result looks like:
this is a number 3.127
this is a number 4.127
this is a number 5.127
Using macro
qa .......................... start record macro 'a'
/iden<Enter> ................ search 'ident*' press Enter
2w .......................... jump 2 words until number one (before dot)
Ctrl-a ...................... increases the number
2w .......................... jump to number after dot
1500 Ctrl-a ................. perform increases 1500 times
q ........................... stop record to macro 'a'
if you have 300 lines with this pattern just now making
300#a