You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Regexp search and replace in files using lookahead and
8
+
Friendly regexp search and replace in files using lookahead and
9
9
backreference to matching groups in the replacement.
10
-
Defaults to global multiline case-insensitive search.
11
-
Needs node v6+.
10
+
Defaults to global multiline case-insensitive search. Will run with any version of Node JS (yes, even v0.6)
11
+
12
12
13
13
Files can be given as [glob notation](https://www.tcl.tk/man/tcl8.5/tutorial/Tcl16a.html), for example the glob `docs/*.md` represents each markdown file in the `docs/` dir.
14
14
15
15
### Install
16
16
```bash
17
17
> npm install -g rexreplace
18
18
```
19
+
19
20
20
21
### Usages
21
22
```bash
@@ -40,9 +41,8 @@ Hard on your fingers to write on your keyboard? We got you covered with `rr` as
40
41
> rexreplace '(f?(o))o(.*)''$3$1$2' myfile.md
41
42
# 'foobar' in myfile.md will become 'barfoo'
42
43
43
-
# Per default '€' is treated as an alias for '$' because some commandline tools have a special relationship with with the `$` char. Your can escape your way out of this old love story but it often popup in unexpected ways.
44
44
> rexreplace '(f?(o))o(.*)''€3€1€2' myfile.md
45
-
#'foobar' in myfile.md will become 'barfoo'
45
+
#As '€' is treated as an alias for '$' this also transforms 'foobar' into 'barfoo'
46
46
47
47
```
48
48
@@ -69,15 +69,20 @@ Hard on your fingers to write on your keyboard? We got you covered with `rr` as
69
69
-h, --help Show help [boolean]
70
70
```
71
71
72
+
### Quirks
73
+
- Per default `€` is treated as an alias for `$`. The main reason is for you not to worry about some commandline tools having a special relationship with with the `$` char. Your can escape your way out of this old love story but it often popup in unexpected ways. Use the `-€` flag if you need to search or replace the actual euro char.
74
+
75
+
### Limitations
76
+
- Reads each file into memory, so using RexReplace on your 3Gb log file will probably not be ideal.
77
+
72
78
### Test
73
-
All tests are defined in [test.sh](https://github.com/mathiasrw/rexreplace/blob/master/test.sh) and after `git clone`ing the repo you can invoke them with:
79
+
All tests are defined in [test.sh](https://github.com/mathiasrw/rexreplace/blob/master/test.sh) and after `git clone`'ing the repo you can invoke them with:
74
80
75
81
```bash
76
82
> npm test
77
83
```
78
84
79
85
### Future ideas
80
-
- Support node 0.12+
81
86
- Test-run a with info outputted about what will happen (sets -v and does not change anything)
82
87
- Let search and replace be withing the names of the files (ask for overwrite. -Y = no questions)
83
88
- Let search and replace be within the path of the files (ask for overwrite. -Y = no questions)
@@ -89,9 +94,10 @@ All tests are defined in [test.sh](https://github.com/mathiasrw/rexreplace/blob/
89
94
- Let pattern, replacement, glob be javascript code returning string as result
90
95
- Error != warning
91
96
- Debug != all debug
97
+
- Flag for sync or async read file handeling. Test if async or sync is best.
varyargs=require('yargs').strict().usage('RexReplace '+version+': Regexp search and replace for files using lookahead and backreference to matching groups in the replacement. Defaults to global multiline case-insensitive search.\n\n> rexreplace searchFor replaceWith filename').example("> rexreplace '(f?(o))o(.*)' '$3$1$2' myfile.md","'foobar' in myfile.md will become 'barfoo'").example('').example("> rexreplace -I 'Foo' 'xxx' myfile.md","'foobar' in myfile.md will remain 'foobar'").example('').example('> rexreplace \'^#\' \'##\' *.md','All markdown files in this dir got all headlines moved one level deeper').version('v','Echo rexreplace version',version).alias('v','version').boolean('I').describe('I','Void case insensitive search pattern.').alias('I','void-ignore-case').boolean('M').describe('M','Void multiline search pattern. Makes ^ and $ match start/end of whole content rather than each line.').alias('M','void-multiline').boolean('u').describe('u','Treat pattern as a sequence of unicode code points.').alias('u','unicode').describe('e','Encoding of files.').alias('e','encoding').default('e','utf8').boolean('o').describe('o','Output the result instead of saving to file. Will also output content even if no replacement have taken place.').alias('o','output')
11
+
//.conflicts('o', 'd')
12
+
13
+
.boolean('q').describe('q',"Only display erros (no other info)").alias('q','quiet').boolean('Q').describe('Q',"Never display erros or info").alias('Q','quiet-total').boolean('H').describe('H',"Halt on first error").alias('H','halt').default('H',false).boolean('d').describe('d',"Print debug info").alias('d','debug').boolean('€').describe('€',"Void having '€' as alias for '$' in pattern and replacement").alias('€','void-euro')
14
+
15
+
/* // Ideas
16
+
.boolean('n')
17
+
.describe('n', "Do replacement on file names instead of file content (rename the files)")
18
+
.alias('n', 'name')
19
+
20
+
.boolean('v')
21
+
.describe('v', "More chatty output")
22
+
.alias('v', 'verbose')
23
+
.boolean('p')
24
+
.describe('p', "Pattern will be piped in. Note that replacement must then be first argument. Other elements like -P and -€ will be applyed afterwards.")
25
+
.alias('p', 'pattern-pipe')
26
+
.boolean('r')
27
+
.describe('r', "Replacement will be piped in. Note that filename/globs must then be second argument")
28
+
.alias('r', 'replacement-pipe')
29
+
30
+
.boolean('P')
31
+
.describe('P', "Pattern is a filename from where the pattern will be generated. Pattern will be defined by each line trimmed and having newlines removed followed by other other rules (like -€).)")
32
+
.alias('P', 'pattern-file')
33
+
.boolean('R')
34
+
.describe('R', "Replacement is a filename from where the replacement will be generated. Replacement will be defined by each line trimmed and having newlines removed followed by other other rules (like -€).")
35
+
.alias('R', 'replacement-file')
36
+
37
+
.boolean('G')
38
+
.describe('G', "filename/globas are filename(s) for files containing one filename/globs on each line to be search/replaced")
39
+
.alias('G', 'globs-file')
40
+
.boolean('g')
41
+
.describe('g', "filename/globs will be piped in. If any filename/globs are given in command the piped data will be prepened")
42
+
.alias('g', 'glob-pipe')
43
+
44
+
.boolean('j')
45
+
.describe('j', "Pattern is javascript source that will return a string giving the pattern to use")
46
+
.alias('j', 'pattern-js')
47
+
48
+
.boolean('J')
49
+
.describe('J', "Replacement is javascript source that will return a string giving the replacement to use to use")
50
+
.alias('j', 'replacement-js')
51
+
52
+
.boolean('glob-js')
53
+
.describe('glob-js', "filename/globs are javascript source that will return a string with newline seperating each glob to work on")
54
+
55
+
*/
56
+
57
+
.help('h').alias('h','help').epilog('What "sed" should have been...');
58
+
59
+
varargs=yargs.argv;
60
+
61
+
debug(args);
62
+
63
+
if(args._.length<3){
64
+
die('Need more than 2 arguments',args._.length+' was found',true);
65
+
}
66
+
67
+
if(!args['€']){
68
+
args._[0]=args._[0].replace('€','$');
69
+
args._[1]=args._[1].replace('€','$');
70
+
}
71
+
72
+
varflags='g';
73
+
if(!args['void-ignore-case']){
74
+
flags+='i';
75
+
}
76
+
if(!args['void-multiline']){
77
+
flags+='m';
78
+
}
79
+
if(args.unicode){
80
+
flags+='u';
81
+
}
82
+
83
+
debug(flags);
84
+
85
+
// Get regex pattern
86
+
varregex=args._.shift();
87
+
try{
88
+
regex=newRegExp(regex,flags);
89
+
}catch(err){
90
+
die('Wrong formatted regexp',regex);
91
+
}
92
+
93
+
// Get replacement
94
+
varreplace=args._.shift();
95
+
96
+
// The rest are files
97
+
varfiles=globs.sync(args._);
98
+
99
+
files
100
+
// Correct filepath
101
+
.map(function(filepath){
102
+
returnpath.normalize(process.cwd()+'/'+filepath);
103
+
})
104
+
105
+
// Find out if any filepaths are invalid
106
+
.filter(function(filepath){
107
+
returnfs.existsSync(filepath) ? true : error('File not found:',filepath);
0 commit comments