Replace 2nd to last line -1 in vi - regex

I am trying to replace the content of 2nd to last-1 line in sed. But I cannot get the addressing correct.
for example: in a file
1
2
3
4
5
I want to do:
1
2,
3,
4,
5
In vi it has to be something like: 2,$-1s/$/,/ but $-1 wont work. please suggest.

This might work for you:
seq 5 | sed '1b;$b;s/$/,/'
1
2,
3,
4,
5

you are close. you need a 'g' at the end of 's' commdn. in vim:
:2,$-1 s/$/,/g
will get the thing done.

Related

Match multiple patterns in any order in any location in a string

What is the shortest way to use grep to match multiple patterns in any order, in any location in a string? Preferably using base R in one short line.
Here's an example:
I want to find all elements that contain all of these two elements in my matches vector, in any order, in any location together in the elements of my_vector, with any characters in between them within the element.
matches <- c("fe", "ve")
# 1 2 3 4 5 6 7 8 9
my_vector <- c("fv", "v", "f", "f_v_e", "fe_ve", "feve", "vefe", "fve" , "a")
# want 5, 6, 7
I can do this:
grep(paste0("(?=.*", paste0(matches, sep = ""), ")", collapse = ""),
my_vector,
perl = TRUE)
[1] 5 6 7
But is there a more concise method? In my example I have two elements to match, but my actual problem has several.
An option to avoid the regex/paste would be
which(grepl(matches[1], my_vector) & grepl(matches[2],my_vector))
#[1] 5 6 7
To make it more dynamic
which(Reduce(`&`, lapply(matches, grepl, my_vector)))
#[1] 5 6 7
Or as #Jota mentioned grep can be used intersect
Reduce(intersect, lapply(matches, grep, my_vector))
If there are many elements in matches, the paste method may not work...

How remove text wrap using vim text editor?

I'm trying to write a vim script for remove the text wrap, I am using the following code but it's doesn't provide exact output. eg \string{this indicate newline} if "this" appears in first line, "indicate" is in second line e.t.c then how I remove text wrap. Is it possible?
:%s/\\string{\zs\(\_[^}]*\)\ze}/\1/gec
Edit based on OP's comment:
for example (i/p): \string{1 <enterkey> 2 <enterkey> 3 <enterkey>
4 <enterkey> 5 <enterkey>}. i need (o/p) \string{1 2 3 4 5}.
Before I have:
\string{1
2
3
4
5
}
After I want:
\string{1 2 3 4 5}
Before I have (new pattern):
\string{1
{2}
{3}
4
5}
After I want:
\string{1 {2} {3} 4 5}
This line does what you want:
%s/\\string{\_[^}]*/\=substitute(submatch(0),"\n",' ','g')/
it changes:
foobar
\string{1
2
3
4
5
}
foobar
into:
foobar
\string{1 2 3 4 5 }
foobar
It would be easier to understand your question if you gave a longer example of text, and what you want to do with it. If I understand correctly, you could like to remove the line wrap on lines that contain \\string{this.
You could use :%g/\\string{this/j. It executes the j command on every line matching the \\string{this pattern.
Input:
some text
\string{this
indicate}
more text
Turns into:
some text
\string{this indicate}
more text

Insert comma between digits in vim using regex (recover csv file whose commas were filtered)

I have a .csv file such as this below:
abcde
12345
1.523.545.5
I would like to use a %s/<regex>/<subs>/g to change the file into this (which means, one digit number possibly followed by a . and another one digit number):
a, b, c, d, e
1, 2, 3, 4, 5
1.5, 2, 3.5, 4, 5.5
I tried %s/\(\w\)[^\.]/\1, /g to match only digits that is NOT followed by a . but I am getting this:
a, c, e
1, 3, 5
1.5, 3.5, 5.5
I am not sure why I have deleted out b and d columns. I am close but not there yet. Any clues?
You need a zero width match, in vim what you need is \#!. :h zero-width to check details.
In vim this line should work for your input example:
%s/\v\w([.].|$)#!/&, /g
or
%s/\v\w(\.\d|$)#!/&, /g
It gives the expected output:
a, b, c, d, e
1, 2, 3, 4, 5
1.5, 2, 3.5, 4, 5.5
Another Vim solution:
:%s/\v\w(\.\d)?\zs\ze\w/, /g
Output:
a, b, c, d, e
1, 2, 3, 4, 5
1.5, 2, 3.5, 4, 5.5
EDIT due to OP update
You should just be able to look for "any \w character" and then, if a . character is found, look for .\d. If it is not found, skip it (you can do this by using (\.\d)? like this:
(\w)(\.\d)?
and simply replaced with
\1\2,
https://regex101.com/r/vK4iE7/2
However, this is not VIM-formatted, so you may need to look into others' answers to see how to format this correctly.
https://regex101.com/r/vK4iE7/3 additionally leaves off the trailing comma.
OLD
Do you want the output to look similar to https://regex101.com/r/vK4iE7/1 where the '.' and the value after it are actually part of the number following that?
Granted, this isn't in VIM formatting (it's PCRE), but I want to ensure that I've got the logic correct:
Searching for
(\.\d)?(\w)
and replaced with
\2\1,
turns
abcde
12345
1.523.545.5
into
a,b,c,d,e,
1,2,3,4,5,
1,2.5,3,4.5,5,.5,
which, unfortunately, does have those trailing commas, and that last .5 in the bottom line.
You can try this:
%s/\(\.[[:digit:]]\)\=\(\w\)/\2\1,/g
which uses the vi regex formatting.
This might work for you (GNU sed):
sed 's/\B/, /g' file

Select text in regex between 2 strings

I have the following line :
3EAM7A 1 3 EI AMANDINE MRV SHP 70 W 0 SH3-A1 1 SHP 70W OVOIDE AI E27 SON PIA PLUS
I'd like to get the string : EI AMANDINE MRV SHP 70 W. So I decided to select the strings between 1 (can also be 2, 3 or 99) and 0 (can also be 1, 2, 3, 4 or 5).
I tried :
(0|1|2|3|99)(.*)(0|1|2|3|4|5)
But I have this result :
EAM7A 1 3 EI AMANDINE MRV SHP 70 W 0 SH3-A1 1 SHP 70W OVOIDE AI E
that is not what I want to obtain.
Do you have an idea in regex to make that selection work ?
Thanks !
You were pretty close! Try this:
\b(?:0|1|2|3|99) ([^0|1|2|3|99].*?) (?:0|1|2|3|4|5)\b
Regex101
I think that you want to match "word" 4 to 9?
Your desired match will be in group 1
^(\S+\s){3}((\S+\s){6})
Enable the multiline option if you have a whole file of subject strings.
You can try with:
\s(?:[0-3]|99)\s([A-Z].*?)\b(?:[0-5])\b
DEMO
and get string by group $1. Or if your language support look around, try:
(?<=\s[0-3]\s|99)[A-Z].+?(?=\s[0-5]\s)
DEMO
to get match directly.
Another solution that is based on matching all initial space + digit sequences:
\b(?:(?:[0-3]|99)\b\s*)+(.*?)\s*\b(?:[0-5])\b
See demo
The result is in Group 1.
With \b(?:(?:[0-3]|99)\b\s*)+ the rightmost number from the allowed leading set is picked.
You can use following regex :
(?:(?:[0-3]|99)\s)+(.*?)\s(?:[0-5])\s
See demo https://regex101.com/r/iX6oE1/6
Also note that for matching a range of number you can use a character class instead of multiple OR.

Find numbers in a file and change their value with perl

I have a file with some data in it but there are a bunch of annoying numbers that are less than one which I wanted to just change to 1 instead of manually doing it. I was wondering how you would do this in perl.
I tried using something like this
perl -pe 's/\d+/$& < 1 ? $&=1 : $&/g' file
This basically just finds all numbers and then checks if they are less then 1. If so then set it to 1 and if not leave it alone. Unfortunately, it will not allow $&=1 to happen since it is a readonly. Is there something else in perl that would achieve this effect?
Example input:
this 1 is a 7 file that
has 0.5 some numbers 4
that are 0.3 less 0.1 than 0.9
one as you see 1.1
Output:
this 1 is a 7 file that
has 1 some numbers 4
that are 1 less 1 than 1
one as you see 1.1
You can just match the numbers that are less than one.. and replace with 1:
perl -pe 's/\b0\.\d+/1/g' file
See DEMO
\b0\.\d+\b
You can try this.Replace by 1.See demo.
https://regex101.com/r/hI0qP0/29