I have a variable which is getting a suffix of {} for some reason.
i.e echo $file
<path to file> {}
This variable when consumed in other commands is now erroring out. How do I remove this empty list that is getting appended to my variable?
Something like regsub {} $file {} file . But that doesn't seem to work
regsub works just fine. Try below:
% set a "file name {}"
file name {}
% regsub -all -- "{}" $a "" x
1
% puts $x
file name
%
Related
I'm trying to edit a verilog file by finding a match in lines of a file and replacing the match by "1'b1". The problem is that the match is a bus with square brackets in the form "busname[0-9]".
for example in this line:
XOR2X1 \S12/gen_fa[8].fa_i/x0/U1 ( .A(\S12/bcomp [8]), .B(abs_gx[8]), .Y(
I need to replace "abs_gx[8]" by "1'b1".
So I tried to find a match by using this code:
#gets abs_gx[8]
set net "\{[lindex $data 0]\}"
#gets 1'b1
set X [lindex $data 1]
#open and read lines of file
set netlist [open "./$circuit\.v" r]
fconfigure $netlist -buffering line
gets $netlist line
#let's assume the line is XOR2X1 \S12/gen_fa[8].fa_i/x0/U1 ( .A(\S12/bcomp [8]), .B(abs_gx[8]), .Y(
if {[regexp "(.*.\[A-X\]\()$net\(\).*)" $line -inline]} {
puts $new "$1 1'b$X $2" }
elseif {[regexp "(.*.\[Y-Z\]\()$net(\).*)" $line]} {
puts $new "$1$2" }
else {puts $new $line}
gets $netlist line
I tried so much things and nothing seems to really match or I get an error because 8 is not a command because [8] gets interpreted as a command.
Any sneaky trick to place a variable in a regex without having it interpreted as a regular expression itself?
If you have an arbitrary string that you want to match exactly as part of a larger regular expression, you should precede all non-alphanumeric characters in the string by a backslash (\). Fortunately, _ is also not special in Tcl's REs, so you can use \W (equivalent to [^\w]) to match the characters you need to fix
set reSafe [regsub -all {\W} $value {\\&}]
If you're going to be doing that a lot, make a helper procedure.
proc reSafe {value} {
regsub -all {\W} $value {\\&}
}
(Yes, I'd like a way of substituting variables more directly, but the RE engine's internals are code I don't want to touch…)
If I understand correctly, you want to substitute $X for $net except when $net is preceded by Y( or Z( in which case you just delete $net. You could avoid the complications of regexp by using string map which just does literal substitutions - see https://www.tcl-lang.org/man/tcl8.6/TclCmd/string.htm#M34 . You would then need to specify the Y( and Z( cases separately, but that's easy enough when there are only two. So instead of the regsub lines you would do:
set line [string map [list Y($net Y( Z($net Z( $net $X] $line]
puts $new $line
I have a huge file. I need to find the line containing the pattern abc_x and replace its value 0.34 to 10% increased value. And then copy the entire file (with replaced values) into a new file. I am new to Tcl, please let me know how to do this.
Thanks in advance.
There are three key stages to this:
Reading the old file in.
Making the update to the data in memory.
Writing the new file out.
The first and third stages are pretty standard:
set f [open input.txt]
set data [read $f]
close $f
set f [open output.txt "w"]
puts -nonewline $f $data
close $f
So now it's just about doing the transformation in memory. The best answer to this depends on the version of Tcl you're using. In all current production versions, it's probably best to split the data into lines and iterate over them, checking whether a line matches and, if it does, performing the transformation.
set lines {}
foreach line [split $data "\n"] {
if {[matchesPattern $line]} {
set line [updateLine $line]
}
lappend lines $line
}
set data [join $lines "\n"]
OK, in that code above, matchesPattern and updateLine are stand-ins for the real code, which might look like this:
if {[regexp {^(\s*abc_x\s+)([\d.]+)(.*)$} $line -> prefix value suffix]} {
# Since we matched the prefix and suffix, we must put them back
set line $prefix[expr {$value * 1.1}]$suffix
}
Composing all those pieces together gets this:
set f [open input.txt]
set data [read $f]
close $f
set lines {}
foreach line [split $data "\n"] {
if {[regexp {^(\s*abc_x\s+)([\d.]+)(.*)$} $line -> prefix value suffix]} {
set line $prefix[expr {$value * 1.1}]$suffix
}
lappend lines $line
}
set data [join $lines "\n"]
set f [open output.txt "w"]
puts -nonewline $f $data
close $f
In 8.7 you'll be able to write the update more succinctly:
set data [regsub -all -line -command {^(\s*abc_x\s+)([\d.]+)} $data {apply {{-> prefix value} {
# Since we matched the prefix, we must put it back
string cat $prefix [expr {$value * 1.1}]
}}}]
(Getting shorter than this would really require a RE engine that supports lookbehinds; Tcl's standard one does not.)
I have to make this command run from my scala code
perl -ne '/pattern/ && print $1 and last' filename
I have tried
val re = """pattern"""
val file = "filename"
val v= (Process(Seq("""perl -ne '/"""+re+"""/ && print $1 and last' """+file))).!!
But some how despite generating the same command required for command line its still not working.It says:
java.io.IOException: Cannot run program "perl -ne '/pattern/ && print $1 and last' file": error=2, No such file or directory.
Can anyone suggest where its going wrong ?
Maybe you need something like this?
val pattern: String = "..." // your pattern
val perlCode = s""" '/$pattern/ && print $$1 and last' """
val v = (Process(Seq("perl", "-ne", perlCode, file))).!!
The issue is Process takes a Sequence of arguments that will be executed. In your case,
perl -ne '/pattern/ && print $1 and last' filename
perl is the first, -ne the second, followed by the perl code /pattern/ && print $1 and last (note that the single quotes ' are not relevant, they are just used to ensure that the string of code is passed as a single argument to perl) and last you have the filename.
The scala.sys.process docs show you pretty much everything. If your file is an java.io.File, try:
val perlCmd = Seq("perl", "-ne", perlCode)
val file = new java.io.File("/tmp/f.txt")
val result = perlCmd #< file !!
Which is the same as
perl -ne '/pattern/ && print $1 and last' < /tmp.txt
TCL/TK:
Problem: I want to be able to get the post-match string data, but even though I provide
regexp with more than a variable for the match itself the secutive variables either turn out empty, or I got the same value from the first two.
E.g:
set args "!do dance"
regsub -all {(!do)} $args prefix command
puts $prefis "!do"
puts $command "!do"
What to do? Ty
EDIT I found the solution thanks to inspiration by your answer, here's a snippet
if { [ regsub {(!do\s+)} $args "" match ] >= 1 } {
if { $match == "{help}" }
Assuming you want to remove the "!do" then you can do the following:
set args "!do dance"
regsub -all {(!do)} $args "" output
puts $output
I'm not sure why you're using regexp here, and it seems like you're using eggdrop or something. You can easily use:
set prefix [lindex $args 0]
set command [lindex $args 1]
Though you should be careful with $args. It's usually used in procs to mean all the other arguments passed on to the proc aside from the already defined arguments.
% puts $prefix
!do
% puts $command
dance
I get a uninitialized value in string eq at *** line xxx warning in my code, which would be easy too fix if there actually was aneq at that line.
But there is a regular expression match on a value inside a hashref.
if ($hashref->{parameters}->{type} =~ m/:/) {
some lines before this I even have this:
$hashref->{parameters} = defined($hashref->{parameters}) ? $hashref->{parameters} : '';
$hashref->{parameters}->{type} = defined($hashref->{parameters}->{type}) ? $hashref->{parameters}->{type} : '';
so the value should be at least initialized.
I'm asking myself and you: why do I still get the warning that the value is uninitialized and moreover why does it say eq instead of pattern match
Edit:
The parameters subhash contains all variabels given via url input (post and/or get).
The type value is one of those variables which could be in the url.
It does not matter if or if not the type value is in the url, and if it contains a value, I always get an uninitialized value in string eq warning. Even if I control the value of type the line by warning it before the buggy line.
2. edit:
As #ikegami supposed there is indeed an elsif which caused the warning
The whole if - elsif statement looks somehow like:
if ($hashref->{parameters}->{type} =~ m/:/) {
…
elsif ($hashref->{parameters}->{type} eq $somevalue) {
…
}
and it was $somevalue that was uninitialized.
You only showed half of the statement on that line. The full statement actually looks something like
456: if ($foo =~ /bar/) {
457: ...
458: }
459: elsif ($baz eq 'qux') {
460: ...
461: }
Run-time warnings for a statement normally use the line number at which the statement started, so if the regex doesn't match and $baz is undefined, you'll get a warning listing line 456 for the eq on line 459.
It's the same idea here:
$ perl -wE' my $x; # 1
say # 2
4 # 3
+ # 4
$x # 5
+ # 6
5; # 7 '
Use of uninitialized value $x in addition (+) at -e line 2.
9
Recently*, Perl was changed so that elsif conditions are considered a different statement to avoid this kind of problem. You must have an older version of Perl.
— Actually, not so recently. Both 5.10 and 5.12 have been end-of-lifed, yet you appear to be using an even older version that that. If you're going to ask questions about a far-obsolete version of Perl, please mention it.
$ perlbrew use 5.10.1
$ perl -we'
my ($x,$y,$z);
if ($x) {
} elsif ($y eq $z) {
}'
Use of uninitialized value $y in string eq at -e line 4.
Use of uninitialized value $z in string eq at -e line 4.
$ perlbrew use 5.8.9
$ perl -we'
my ($x,$y,$z);
if ($x) {
} elsif ($y eq $z) {
}'
Use of uninitialized value in string eq at -e line 3.
Use of uninitialized value in string eq at -e line 3.