Deano
Deano

Reputation: 12190

regex match first occurrence in file

I'm trying to insert new object to feLinks array therefore I'm trying to target closing array tag ]; so I can append an object to the array.

I'm trying to match the first occurrence of ]; so I could inject a new object

I do know about lazy quantifier, but haven't been able to make it work.

var fedLinks = [{
    Name:" Test",
    data:'value',
    tag:"first"
}];

var fedSet = [
{
    Name:"Dashboard",
    data:fedLinks
}];

Here is what I have tried

];.+? 

But it returns no match

Upvotes: 0

Views: 458

Answers (2)

Ed Morton
Ed Morton

Reputation: 203502

Use awk with literal strings for robustness, portability, and clarity (none of which you can have with a sed solution):

awk '
    NR==FNR{ add=(NR>1 ? add ORS : "") $0; next }
    s=index($0,"];") { $0=substr($0,1,s-1) add substr($0,s); add="" }
1' add.txt test.txt

The above reads the new record as a literal string from the file "add.txt" then inserts that just before the literal string "];" appears in "test.txt" and prints the result, again as a literal string. That way you don't have to worry about escape characters or regexp metacharacters or backreferences or anything else in either input file - everything will be reproduced exactly as you typed it. It will also work as-is with any awk on any UNIX box.

For example (borrowing @Weike's sample added text):

$ cat test.txt
var fedLinks = [{
    name: "test1",
    data: "value1",
    tag: "first"
}];

var fedSet = [
{
    name: "Dashboard",
    data: fedLinks
}];

.

$ cat add.txt
,{
    name: "test2",
    data: "value2",
    tag: "second"
}

.

$ awk 'NR==FNR{add=(NR>1 ? add ORS : "") $0; next} s=index($0,"];"){$0=substr($0,1,s-1) add substr($0,s); add=""} 1' add.txt test.txt
var fedLinks = [{
    name: "test1",
    data: "value1",
    tag: "first"
},{
    name: "test2",
    data: "value2",
    tag: "second"
}];

var fedSet = [
{
    name: "Dashboard",
    data: fedLinks
}];

Upvotes: 1

Weike
Weike

Reputation: 1270

Solution 1:

$ sed -nr ':start;/\];/!{p;n;bstart};SUBSTITUTE;:end;p;n;bend'

Explains:

  1. :start;/\];/!{p;n;bstart}: use a loop to print the line what it is util matching the first line containing \];.
  2. use SUBSTITUTE to insert a new object to first array.
  3. :end;p;n;bend: use a new loop to print the lines after the with the first ];.

Here, I'll use s command to substitute the null char between } & ] with your new object:

s/(})(])/\1,{\n    name: "test2",\n    data: "value2",\n    tag: "second"\n}\2/

for example:

$ cat test.txt 
var fedLinks = [{
    name: "test1",
    data: "value1",
    tag: "first"
}];

var fedSet = [
{
    name: "Dashboard",
    data: fedLinks
}];

we want to add another object to fedLinks array:

$ sed -nr ':start;/\];/!{p;n;bstart};s/(\})(\])/\1,{\n    name: "test2",\n    data: "value2",\n    tag: "second"\n}\2/;:end;p;n;bend' test.txt
var fedLinks = [{
    name: "test1",
    data: "value1",
    tag: "first"
},{
    name: "test2",
    data: "value2",
    tag: "second"
}];

var fedSet = [
{
    name: "Dashboard",
    data: fedLinks
}];

Solution 2:

We can change the way of thinking how to achieve functional. Instead of finding the first }];, we can find complete feLinks array block, then do your insert operations.

$ sed -r '/fedLinks.*\[\{/!bend;:loop;N;/\}\]/{SUBSTITUTE;bend};bloop;:end'

Explains:

  1. fedLinks.*\[\{: find the beginning of the array which you want to insert a new object; or just jump to label end to read next line from stream.
  2. :loop: set a label loop to read the remaining lines which belong to the fedLinks array.
  3. N;...;bloop: append \n and next line from stream into pattern space util matching the \}\], which means the end of fedLinks array.
  4. /\}\]/{SUBSTITUTE;bend};bloop: deal with the fedLinks array when fetching all lines belonged to the fedLinks array and then jump to label end.

for example:

$ sed -r '/fedLinks.*\[\{/!bend;:loop;N;/\}\]/{s/(})(])/\1,{\n    name: "test2",\n    data: "value2",\n    tag: "second"\n}\2/;bend};bloop;:end' test.txt
var fedLinks = [{
    name: "test1",
    data: "value1",
    tag: "first"
},{
    name: "test2",
    data: "value2",
    tag: "second"
}];

var fedSet = [
{
    name: "Dashboard",
    data: fedLinks
}];

Upvotes: 1

Related Questions