Incrementing an integer at the end of a string in perl - perl

I have a string in the following format:
\main\stream\foo.h\3
it may have more or less "sections", but will always end with a slash followed by an integer. Other examples include:
\main\stream2309\stream222\foo.c\45
\main\foo.c\9
I need to, in Perl, increment the number at the end of the string and leave the rest alone. I found an example on this site that does exactly what I want to do (see Increment a number in a string in with regex) only the language is Javascript. The solution given was:
.replace(/\d+$/,function(n) { return ++n })
I need to do the same thing in Perl.

You can use the /e regex modifier to put executable code in your replacement string.
Something like:
$string =~ s/(\d+)$/$1 + 1/e;
should work.

Try $var =~ s/(\d+$)/($1 + 1)/e

Related

How to identify a character in a string?

I am trying to write a Powershell code to identify a string with a specific character from a filename from multiple files.
An example of a filename
20190902091031_202401192_50760_54206_6401.pdf
$Variable = $Filename.Substring(15,9)
Results:
202401192 (this is what I am after)
However in some instances the filename will be like below
20190902091031_20240119_50760_54206_6401.pdf
$Variable = $Filename.Substring(15,9)
Results:
20240119_ (this is NOT what I am after)
I am trying to find a code to identify the 9th character,
IF the 9th character = "_"
THEN Set
$Variable = $Filename.Substring(15,8)
Results:
20240119
All credit to TheMadTechnician who beat me to the punch with this answer.
To expand on the technique a bit, use the split method or operator to split a string every time a certain character shows up. Your data is separated by the underscore character, so is a perfect example of using this technique. By using either of the following:
$FileName.Split('_')
$FileName -split '_'
You can turn your long string into an array of shorter strings, each containing one of the parts of your original string. Since you want the 2nd one, you use the array descriptor [1] (0 is 1st) and you're done.
Good luck

Retrieving String with single quotes from database and storing in Perl

I have a SQL query
select name from Employee
Output :
Sharma's
How can I store this output in perl string.
I tried below :
$sql =qq {select Name from Employee};
$Arr = &DataBaseQuery( $dbHandle, $sql );
$name = $Arr;
But when I print $name I get output as
Sharma::s
How can I store the single quote in the $name.
First of all, non of standard DBI/DBD exibits behavior you listed, in my experience.
Without knowing details of what DataBaseQuery() does it's impossible to answer conclusively, but a plausible theory can be formed:
Apostrophe is a valid package separator in Perl, equivalent to "::".
Reference: perldoc perlmod
The old package delimiter was a single quote, but double colon is now the preferred delimiter, in part because it's more readable to humans, and in part because it's more readable to emacs macros. It also makes C++ programmers feel like they know what's going on--as opposed to using the single quote as separator, which was there to make Ada programmers feel like they knew what was going on. Because the old-fashioned syntax is still supported for backwards compatibility, if you try to use a string like "This is $owner's house" , you'll be accessing $owner::s ; that is, the $s variable in package owner , which is probably not what you meant. Use braces to disambiguate, as in "This is ${owner}'s house" .
perl -e 'package A::B; $A::B=1; 1;
package main;
print "double-colon: $A::B\n";
print "apostrophe: $A'"'"'B\n";'
double-colon: 1
apostrophe: 1
I have a strong suspicion something within your own libraries inside DataBaseQuery() call was written to be "smart" and to convert apostrophes to double-colons because of this.
If you can't figure out root cause, you can always do one of the following:
Write your own DB wrapper
Assuming your text isn't likely to contain "::", run a regex to fix s#::#'#g; on all results from DataBaseQuery() (likely, in a function serving as a wrapper-replacement for DataBaseQuery())

How does this Perl one-liner actually work?

So, I happened to notice that last.fm is hiring in my area, and since I've known a few people who worked there, I though of applying.
But I thought I'd better take a look at the current staff first.
Everyone on that page has a cute/clever/dumb strapline, like "Is life not a thousand times too short for us to bore ourselves?". In fact, it was quite amusing, until I got to this:
perl -e'print+pack+q,c*,,map$.+=$_,74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34'
Which I couldn't resist pasting into my terminal (kind of a stupid thing to do, maybe), but it printed:
Just another Last.fm hacker,
I thought it would be relatively easy to figure out how that Perl one-liner works. But I couldn't really make sense of the documentation, and I don't know Perl, so I wasn't even sure I was reading the relevant documentation.
So I tried modifying the numbers, which got me nowhere. So I decided it was genuinely interesting and worth figuring out.
So, 'how does it work' being a bit vague, my question is mainly,
What are those numbers? Why are there negative numbers and positive numbers, and does the negativity or positivity matter?
What does the combination of operators +=$_ do?
What's pack+q,c*,, doing?
This is a variant on “Just another Perl hacker”, a Perl meme. As JAPHs go, this one is relatively tame.
The first thing you need to do is figure out how to parse the perl program. It lacks parentheses around function calls and uses the + and quote-like operators in interesting ways. The original program is this:
print+pack+q,c*,,map$.+=$_,74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34
pack is a function, whereas print and map are list operators. Either way, a function or non-nullary operator name immediately followed by a plus sign can't be using + as a binary operator, so both + signs at the beginning are unary operators. This oddity is described in the manual.
If we add parentheses, use the block syntax for map, and add a bit of whitespace, we get:
print(+pack(+q,c*,,
map{$.+=$_} (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21,
18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34)))
The next tricky bit is that q here is the q quote-like operator. It's more commonly written with single quotes:
print(+pack(+'c*',
map{$.+=$_} (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21,
18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34)))
Remember that the unary plus is a no-op (apart from forcing a scalar context), so things should now be looking more familiar. This is a call to the pack function, with a format of c*, meaning “any number of characters, specified by their number in the current character set”. An alternate way to write this is
print(join("", map {chr($.+=$_)} (74, …, -34)))
The map function applies the supplied block to the elements of the argument list in order. For each element, $_ is set to the element value, and the result of the map call is the list of values returned by executing the block on the successive elements. A longer way to write this program would be
#list_accumulator = ();
for $n in (74, …, -34) {
$. += $n;
push #list_accumulator, chr($.)
}
print(join("", #list_accumulator))
The $. variable contains a running total of the numbers. The numbers are chosen so that the running total is the ASCII codes of the characters the author wants to print: 74=J, 74+43=117=u, 74+43-2=115=s, etc. They are negative or positive depending on whether each character is before or after the previous one in ASCII order.
For your next task, explain this JAPH (produced by EyesDrop).
''=~('(?{'.('-)#.)#_*([]#!#/)(#)#-#),#(##+#)'
^'][)#]`}`]()`#.#]#%[`}%[#`#!##%[').',"})')
Don't use any of this in production code.
The basic idea behind this is quite simple. You have an array containing the ASCII values of the characters. To make things a little bit more complicated you don't use absolute values, but relative ones except for the first one. So the idea is to add the specific value to the previous one, for example:
74 -> J
74 + 43 -> u
74 + 42 + (-2 ) -> s
Even though $. is a special variable in Perl it does not mean anything special in this case. It is just used to save the previous value and add the current element:
map($.+=$_, ARRAY)
Basically it means add the current list element ($_) to the variable $.. This will return a new array with the correct ASCII values for the new sentence.
The q function in Perl is used for single quoted, literal strings. E.g. you can use something like
q/Literal $1 String/
q!Another literal String!
q,Third literal string,
This means that pack+q,c*,, is basically pack 'c*', ARRAY. The c* modifier in pack interprets the value as characters. For example, it will use the value and interpret it as a character.
It basically boils down to this:
#!/usr/bin/perl
use strict;
use warnings;
my $prev_value = 0;
my #relative = (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34);
my #absolute = map($prev_value += $_, #relative);
print pack("c*", #absolute);

replace string1 with string2 in many java files, only in comments

I have around 3000 instance of replacement done in hundreds of files. Replacing all occurance of string1 with string2 was easy. IntelliJ allows me to replace all occurences in "comments and strings".
The problem is that the same string appear in comments and real code. I would like restrict the replacement only in comment section ( we use mix of /**/ or // )
Any library/IDE/script that can do this?
use Regexp::Common 'comment';
...
s/($RE{comment}{'C++'})/(my $x = $1) =~ s#string1#string2#g; $x/ge;
Try using the following regex to find all comments, and then replace what you want afterwards:
/(?>\/\*[^\*\/]*\*\/|\/\/([^\n])*\n)/
The first part \/\*[^\*\/]*\*\/ Tries to find all /**/ pairs where it finds something that starts with /* and then contains something other than end tag */ and the contains end tag */.
THe other part checks something that starts with // and goes to endline(\n) and contains something not newline between ([^\n]*).
Thus it should all comments

Difference between "52" and 52?

Guys perl is not as easy i thought its so confusing thing.I just moved to operators and I wrote some codes but I am unable to figure it out how the compiler treating them.
$in = "42" ;
$out = "56"+32+"good";
print $out,;
The output for above code is 88 and where does the good gone? and Now lets see the other one.
$in ="42";
$out="good52"+32;
print $out ;
and for these the output is 32. The question is where does the good gone that we just stored in $out and the value 52 between the " "why the compiler just printing the value as 32 but not that remaining text.And the other question is
$in=52;
$in="52";
both doing the same work "52" not working as a text . becuase when we add "52"+32 it gives as 84. what is happening and
$in = "hello";
$in = hello;
both do the same work ? or do they differ but if i print then give the same output.Its just eating up my brain.Its so confusing becuase when "52" or 52 and "hello" or hello doing the same job why did they introduce " ".I just need the explaination why its happening for above codes.
In Perl, + is a numeric operator. It tries to interpret its two operands as numbers. 51 is the number 51. "51" is a string containing two digits, and the + operator tries to convert the string to a number, which is 51, and uses it in the calculation. "hello" is a string containing five letters, and when the + operator tries to interpret that as a number, it equates to 0 (zero).
Your first example is thus:
$out = "56"+32+"good";
which is evaluates just like:
$out = 56 + 32 + 0;
Your print then converts that to a string on output, and yields 88.
In perl, the + operator will treat its arguments as numbers, and try to convert anything that is not a number to a number. The . (dot) operator is used to join strings: it will try to convert its operands to strings if they aren't already strings.
If you put:
use strict;
use warnings;
At the top of your script, you would get warnings such as:
Argument "good" isn't numeric in addition (+) at ...
Argument "good52" isn't numeric in addition (+) at ...
Perl automatically reassigns a string value to numeric, if possible. So "42" + 10 actually becomes 52. But it cannot do that with a proper string value, such as "good".
In perl, a string in a numerical context (like when you use a + operator) is converted to a number.
In perl, you can concatenate string using the . (dot) operator, not +.
If you use +, perl will try and interpret all of the operands as numbers. This works well for strings that are number representations, otherwise you get 0. This explains what you see.
$in=52;
$in="52";
both doing the same work "52" not working as a text . becuase when we add "52"+32 it gives as 84.
The problem here is not with the variable definition. One is a string and the other a number. But when you use the string in a numerical expression (+), then it will converted to number.
About your second question:
$in = "hello" defines a string, as you expect;
$in = hello; will just copy the symbol hello (however it is defined) on to your variable. This is actually not "strict" perl and if you set use strict; in your file, perl will complain about it.
First off, give this a read.
Your problem is that the + is a mathematical addition, which doesn't work on strings. If you use that, Perl will assume that you're working with numbers and therefore discard anything that isn't.
To concatenate strings, use .:
$str = "blah " . "blah " . "blah";
As far as the difference between "52" and 52 goes, there isn't one. Since nothing (commands, comments, etc.) in Perl can start with numbers, the compiler doesn't need the quotes to know what to do.