I want to compare two strings in TCL and replace the unmatched character with asterisk.
Core_cpuss_5/loop2/hex_reg[89]cpu_ip[45]_reg10/D[23]
Core_cpuss_5/loop2/hex_reg[56]cpu_ip[12]_reg5/D[33]
Output Required : Core_cpuss_5/loop2/hex_reg[ * ]cpu_ip[ * ]_reg*/D[*]
I tried above using regsub but not working as expected.
foreach v {string1 string2} {
regsub {\[[0-9]+\]$} $v {[*]} v_modified
}
To replace the integers inside the square brackets with * (and also change reg10 and reg5 to reg*)
set string1 {Core_cpuss_5/loop2/hex_reg[89]cpu_ip[45]_reg10/D[23]}
set string2 {Core_cpuss_5/loop2/hex_reg[56]cpu_ip[12]_reg5/D[33]}
foreach v "$string1 $string2" {
regsub -all {\[\d+\]} $v {[*]} v_modified
regsub -all {reg\d+} $v_modified {reg*} v_modified
puts $v_modified
}
You had a couple problems in your code which I fixed:
Change {string1 string2} to "$string1 $string2"
Add -all to the regexp command find all matches.
Remove the $ from the regular expression because that only matches the final one.
Add another regsub to change reg10 and reg5 to reg*.
If you need a more general purpose solution, this will find a sequence of integers in each string and replace with a * if they are different:
set string1 {Core_cpuss_5/loop2/hex_reg[89]cpu_ip[45]_reg10/D[23]}
set string2 {Core_cpuss_5/loop2/hex_reg[56]cpu_ip[12]_reg5/D[33]}
# Initialize start positions for regexp for each string.
set start1 0
set start2 0
# Incrementally search for integers in each string.
while {1} {
# Find a match for an integer in each string and save the {begin end} indices of the match
set matched1 [regexp -start $start1 -indices {\d+} $string1 indices1]
set matched2 [regexp -start $start2 -indices {\d+} $string2 indices2]
if {$matched1 && $matched2} {
# Use the indices to get the matched integer
set value1 [string range $string1 {*}$indices1]
set value2 [string range $string2 {*}$indices2]
# Replace the integer with *
if {$value1 ne $value2} {
set string1 [string replace $string1 {*}$indices1 "*"]
set string2 [string replace $string2 {*}$indices2 "*"]
}
} else {
break
}
# Increment the start of the next iteration.
set start1 [expr {[lindex $indices1 1]+1}]
set start2 [expr {[lindex $indices2 1]+1}]
}
puts "String1 : $string1"
puts "String2 : $string2"
The above will only work if the two strings are similar enough (like they each have the same number of integers in a similar order)
I need to concatenate partial content from argv to one of my variable.
I will show you my code:
#!/bin/csh
set stringList = ""
foreach param ($argv)
if($param !~ TEST) then
set stringList = $stringList " " $param
endif
end
echo $stringList > /tmp/prova.txt
Of course, nothing is printed on the txt file.
Any solution? Thanks.
Change
set stringList = $stringList " " $param
to
set stringList = "$stringList $param"
I have a snippet of code that I use for a program that I have [Thus some of the app specific code] ...Anyway I am trying to capitalize the first letter of each word unless the word is in caps.
for example: >>this is text THAT would be CHANGED.
The code that i have thus far is as follows.
Again some of this is app specific I am not able to use "puts," the result has to be returned as return "" this is the reason that I create a var and add to it word by word.
proc ToTitle {} {
set Input [sh_set clipboard]
set CleanedInput [string map {" " |} [string trimright [string trimleft $Input]]]
set InputList [split $CleanedInput "|"]
set wresult ""
set item 0
foreach line $InputList {
set List_Item [lindex $InputList $item];
if {[string is upper $List_Item] == 1} {
set newline $List_Item
set wresult "$wresult $newline"
incr item
} else {
set newline [string totitle $List_Item]
set wresult "$wresult $newline"
incr item
}
}
regsub -all {\u0020{2,}} $wresult " " wresult; #REMOVE ALL EXCESSIVE SPACE CHARACTERS
set $wresult [string trimright [string trimleft $wresult]]; # TRIM ALL OF THE WHITESPACE BEFORE AND AFTER THE STRING
return "$wresult"}
This is currently working the output would be:
This Is Text THAT Would Be Changed.
The issue is the "Changed." because of the "."
The question is What can I use to only read the word character on items that have special characters or word characters?
{[string is upper $List_Item] == 1}
I know there is something that I can add to that to check it...
Thankyou in advance for all the help.
I think there's a simpler solution. Try this:
set a "this is text THAT would be CHANGED."
set out ""
foreach word $a {
append out "[string toupper $word 0 0] "
}
puts $out
Running it gives this output:
% % % This Is Text THAT Would Be CHANGED.
I need to concatenate partial content from argv to one of my variable.
I will show you my code:
#!/bin/csh
set stringList = ""
foreach param ($argv)
if($param !~ TEST) then
set stringList = $stringList " " $param
endif
end
echo $stringList > /tmp/prova.txt
Of course, nothing is printed on the txt file.
Any solution? Thanks.
Change
set stringList = $stringList " " $param
to
set stringList = "$stringList $param"
Given pairs of string like this.
my $s1 = "ACTGGA";
my $s2 = "AGTG-A";
# Note the string can be longer than this.
I would like to find position and character in in $s1 where it differs with $s2.
In this case the answer would be:
#String Position 0-based
# First col = Base in S1
# Second col = Base in S2
# Third col = Position in S1 where they differ
C G 1
G - 4
I can achieve that easily with substr(). But it is horribly slow.
Typically I need to compare millions of such pairs.
Is there a fast way to achieve that?
Stringwise ^ is your friend:
use strict;
use warnings;
my $s1 = "ACTGGA";
my $s2 = "AGTG-A";
my $mask = $s1 ^ $s2;
while ($mask =~ /[^\0]/g) {
print substr($s1,$-[0],1), ' ', substr($s2,$-[0],1), ' ', $-[0], "\n";
}
EXPLANATION:
The ^ (exclusive or) operator, when used on strings, returns a string composed of the result of an exclusive or on each bit of the numeric value of each character. Breaking down an example into equivalent code:
"AB" ^ "ab"
( "A" ^ "a" ) . ( "B" ^ "b" )
chr( ord("A") ^ ord("a") ) . chr( ord("B") ^ ord("b") )
chr( 65 ^ 97 ) . chr( 66 ^ 98 )
chr(32) . chr(32)
" " . " "
" "
The useful feature of this here is that a nul character ("\0") occurs when and only when the two strings have the same character at a given position. So ^ can be used to efficiently compare every character of the two strings in one quick operation, and the result can be searched for non-nul characters (indicating a difference). The search can be repeated using the /g regex flag in scalar context, and the position of each character difference found using $-[0], which gives the offset of the beginning of the last successful match.
Use binary bit ops on the complete strings.
Things like $s1 & $s2 or $s1 ^ $s2 run incredibly fast, and work with strings of arbitrary length.
I was bored on Thanksgiving break 2012 and answered the question and more. It will work on strings of equal length. It will work if they are not. I added a help, opt handling just for fun. I thought someone might find it useful.
If you are new to PERL add don't know. Don't add any code in your script below DATA to the program.
Have fun.
./diftxt -h
usage: diftxt [-v ] string1 string2
-v = Verbose
diftxt [-V|--version]
diftxt [-h|--help] "This help!"
Examples: diftxt test text
diftxt "This is a test" "this is real"
Place Holders: space = "·" , no charater = "ζ"
cat ./diftxt
----------- cut ✂----------
#!/usr/bin/perl -w
use strict;
use warnings;
use Getopt::Std;
my %options=();
getopts("Vhv", \%options);
my $helptxt='
usage: diftxt [-v ] string1 string2
-v = Verbose
diftxt [-V|--version]
diftxt [-h|--help] "This help!"
Examples: diftxt test text
diftxt "This is a test" "this is real"
Place Holders: space = "·" , no charater = "ζ"';
my $Version = "inital-release 1.0 - Quincey Craig 11/21/2012";
print "$helptxt\n\n" if defined $options{h};
print "$Version\n" if defined $options{V};
if (#ARGV == 0 ) {
if (not defined $options{h}) {usage()};
exit;
}
my $s1 = "$ARGV[0]";
my $s2 = "$ARGV[1]";
my $mask = $s1 ^ $s2;
# setup unicode output to STDOUT
binmode DATA, ":utf8";
my $ustring = <DATA>;
binmode STDOUT, ":utf8";
my $_DIFF = '';
my $_CHAR1 = '';
my $_CHAR2 = '';
sub usage
{
print "\n";
print "usage: diftxt [-v ] string1 string2\n";
print " -v = Verbose \n";
print " diftxt [-V|--version]\n";
print " diftxt [-h|--help]\n\n";
exit;
}
sub main
{
print "\nOrig\tDiff\tPos\n----\t----\t----\n" if defined $options{v};
while ($mask =~ /[^\0]/g) {
### redirect stderr to allow for test of empty variable with error message from substr
open STDERR, '>/dev/null';
if (substr($s2,$-[0],1) eq "") {$_CHAR2 = "\x{03B6}";close STDERR;} else {$_CHAR2 = substr($s2,$-[0],1)};
if (substr($s2,$-[0],1) eq " ") {$_CHAR2 = "\x{00B7}"};
$_CHAR1 = substr($s1,$-[0],1);
if ($_CHAR1 eq "") {$_CHAR1 = "\x{03B6}"} else {$_CHAR1 = substr($s1,$-[0],1)};
if ($_CHAR1 eq " ") {$_CHAR1 = "\x{00B7}"};
### Print verbose Data
print $_CHAR1, "\t", $_CHAR2, "\t", $+[0], "\n" if defined $options{v};
### Build difference list
$_DIFF = "$_DIFF$_CHAR2";
### Build mask
substr($s1,"$-[0]",1) = "\x{00B7}";
} ### end loop
print "\n" if defined $options{v};
print "$_DIFF, ";
print "Mask: \"$s1\"\n";
} ### end main
if ($#ARGV == 1) {main()};
__DATA__
This is the easiest form you can get
my $s1 = "ACTGGA";
my $s2 = "AGTG-A";
my #s1 = split //,$s1;
my #s2 = split //,$s2;
my $i = 0;
foreach (#s1) {
if ($_ ne $s2[$i]) {
print "$_, $s2[$i] $i\n";
}
$i++;
}