Replace once part of the query in Emacs - emacs

I have such requirement for search&replace in Emacs:
I have a bunch of
'A', 'High'
'B', 'High'
'C', 'High'
'D', 'High'
And the list goes on.
I want to replace them to be:
A = 'High'
B = 'High'
C = 'High'
D = 'High'
Can I query for the pattern, say '#', 'High' and replace it with #= 'High?

Move point to beginning of buffer.
M-x query-replace-regexp.
Enter '\([^']+\)', '\([^']+\)' as regexp and \1 = '\2' as replacement.
Press ! to replace all at once, or keep pressing y/n
for each match.

Related

Powershell .TrimEnd not returning correct result

Running the following
$x = "CF21_flddep-op-config"
$x.TrimEnd("-op-config")
Results in:
CF21_fldde
When it should be displaying:
CF21_flddep
Any ideas why?
.TrimEnd() does not remove a trailing string, it removes a set of trailing characters. p is in that set, so the last p is also removed. (You would get the same result with .TrimEnd("-cfginop"), or more explicitly .TrimEnd('-', 'c', 'f', 'g', 'i', 'n', 'o', 'p').) You want something like $x -replace "-op-config", "" or, if the string must only be removed when it occurs at the end, -replace "-op-config$", "".

What is wrong with this Perl subroutine?

I'm trying to implement a subroutine that calculates the d-neighbors of an input string. This is apart of an implementation of planted motif search, but my question is much more general. Here is the code:
#subroutine for generating d-neighbors
sub generate_d_neighbors{
# $sequence is the sequence to generate d-neighbors from
# $HD is the Hamming Distance
my ($sequence, $HD) = #_;
for(my $i = 0; $i=$HD; $i++){
my #l = ['A', 'C', 'T', 'G'];
my #t = splice(#l,$sequence[$i]);
#TODO
}
}
The error is occurring at the last line, saying that:
Global symbol "#sequence" requires explicit package name (did you forget to declare "my #sequence"?
It was my understanding that Perl does not take parameters in the form subroutine(param1, param2) like in Java for example, but why is $sequence not being recognized as already having been initialized?
There are some problems with your code:
sub generate_d_neighbors{
my ($sequence, $HD) = #_;
for(my $i = 0; $i=$HD; $i++){
my #l = ['A', 'C', 'T', 'G'];
my #t = splice(#l,$sequence[$i]);
}
}
First, let's look at
for(my $i = 0; $i=$HD; $i++){
Assuming $HD is nonzero, this loop will never terminate because the condition will never be false. If you wanted $i to range from 0 to $HD, writing the statement as for my $i (0 .. $HD) would have been better.
Second, you have
my #t = splice(#l,$sequence[$i]);
where you seem to assume there is an array #sequence and you are trying to access its first element. However, $sequence is a reference to an array. Therefore, you should use
$sequence->[$i]
Third (thanks #Ikegami), you have
my #l = ['A', 'C', 'T', 'G'];
in the body of the for-loop. Then #l will contain a single element, a reference to an anonymous array containing the elements 'A', 'C', 'T', and 'G'. Instead, use:
my #l = qw(A C T G);
I am not sure exactly what you want to achieve with splice(#l, $sequence->[$i]), but that can be better written as:
my #t = #l[0 .. ($sequence->[$i] - 1)];
In fact, you could reduce the two assignments to:
my #t = qw(A C T G)[0 .. ($sequence->[$i] - 1)];
It looks to me like you want
substring($sequence, 0, 1)
instead of
$sequence[0].
In Perl, strings are first class variables, not a type of array.
Or maybe you want splice(#l, $sequence->[0])?
This list-assignment syntax:
my (#sequence, $HD) = #_;
doesn't do what you might want it to do (put the last argument in $HD and the rest in #sequence). The array always takes all the arguments it can, leaving none for whatever comes after it.
Reversing the order can work, for cases where there is only one array:
my ($HD, #sequence) = #_;
and you make the corresponding change in the caller.
To solve the problem more generally, use a reference:
my ($sequence, $HD) = #_;
and call the sub like this:
generate_d_neighbors(\#foo, $bar);
or this:
# Note the brackets, which make an array reference, unlike parentheses
# which would result in a flat list.
generate_d_neighbors([...], 42);
If you use a prototype:
sub generate_d_neighbors (\#$)
then the caller can say
generate_d_neighbors(#foo, $bar);
and the #foo automatically becomes a reference as if it had been\#foo.
If you use any of the reference-based solutions, you must alter the body of the function to use $sequence instead of #sequence, following these rules:
Change #sequence to #$sequence
Change $#sequence to $#$sequence
Change $sequence[...] to $sequence->[...]
Change #sequence[...] to #$sequence[...] (but be sure you really meant to use an array slice... if you're new to perl you probably didn't mean it, and should have used $sequence[...] instead)

How do I make Marpa's sequence rules greedy?

I am working on a Marpa::R2 grammar that groups items in a text. Each group can only contain items of a certain kind, but is not explicitly delimited. This causes problems, because x...x (where . represents an item that can be part of a group) can be grouped as x(...)x, x(..)(.)x, x(.)(..)x, x(.)(.)(.)x. In other words, the grammar is highly ambiguous.
How can I remove this ambiguity if I only want the x(...)x parse, i.e. if I want to force a + quantifier to only behave “greedy” (as it does in Perl regexes)?
In the below grammar, I tried adding rank adverbs to the sequence rules in order to prioritize Group over Sequence, but that doesn't seem to work.
Below is a test case that exercises this behaviour.
use strict;
use warnings;
use Marpa::R2;
use Test::More;
my $grammar_source = <<'END_GRAMMAR';
inaccessible is fatal by default
:discard ~ space
:start ::= Sequence
Sequence
::= SequenceItem+ action => ::array
SequenceItem
::= WORD action => ::first
| Group action => ::first
Group
::= GroupItem+ action => [name, values]
GroupItem
::= ('[') Sequence (']') action => ::first
WORD ~ [a-z]+
space ~ [\s]+
END_GRAMMAR
my $input = "foo [a] [b] bar";
diag "perl $^V";
diag "Marpa::R2 " . Marpa::R2->VERSION;
my $grammar = Marpa::R2::Scanless::G->new({ source => \$grammar_source });
my $recce = Marpa::R2::Scanless::R->new({ grammar => $grammar });
$recce->read(\$input);
my $parse_count = 0;
while (my $value = $recce->value) {
is_deeply $$value, ['foo', [Group => ['a'], ['b']], 'bar'], 'expected structure'
or diag explain $$value;
$parse_count++;
}
is $parse_count, 1, 'expected number of parses';
done_testing;
Output of the test case (FAIL):
# perl v5.18.2
# Marpa::R2 2.09
ok 1 - expected structure
not ok 2 - expected structure
# Failed test 'expected structure'
# at - line 38.
# Structures begin differing at:
# $got->[1][2] = Does not exist
# $expected->[1][2] = ARRAY(0x981bd68)
# [
# 'foo',
# [
# 'Group',
# [
# 'a'
# ]
# ],
# [
# ${\$VAR1->[1][0]},
# [
# 'b'
# ]
# ],
# 'bar'
# ]
not ok 3 - expected number of parses
# Failed test 'expected number of parses'
# at - line 41.
# got: '2'
# expected: '1'
1..3
# Looks like you failed 2 tests of 3.
Sequence rules are designed for non-tricky cases. Sequence rules can always be rewritten as BNF rules when the going gets tricky, and that is what I suggest here. The following makes your test work:
use strict;
use warnings;
use Marpa::R2;
use Test::More;
my $grammar_source = <<'END_GRAMMAR';
inaccessible is fatal by default
:discard ~ space
# Three cases
# 1.) Just one group.
# 2.) Group follows by alternating words and groups.
# 3.) Alternating words and groups, starting with words
Sequence ::= Group action => ::first
Sequence ::= Group Subsequence action => [values]
Sequence ::= Subsequence action => ::first
Subsequence ::= Words action => ::first
# "action => [values]" makes the test work unchanged.
# The action for the next rule probably should be
# action => [name, values] in order to handle the general case.
Subsequence ::= Subsequence Group Words action => [values]
Words ::= WORD+ action => ::first
Group
::= GroupItem+ action => [name, values]
GroupItem
::= ('[') Sequence (']') action => [value]
WORD ~ [a-z]+
space ~ [\s]+
END_GRAMMAR
my $input = "foo [a] [b] bar";
diag "perl $^V";
diag "Marpa::R2 " . Marpa::R2->VERSION;
my $grammar = Marpa::R2::Scanless::G->new( { source => \$grammar_source } );
my $recce = Marpa::R2::Scanless::R->new( { grammar => $grammar } );
$recce->read( \$input );
my $parse_count = 0;
while ( my $value = $recce->value ) {
is_deeply $$value, [ 'foo', [ Group => ['a'], ['b'] ], 'bar' ],
'expected structure'
or diag explain $$value;
$parse_count++;
} ## end while ( my $value = $recce->value )
is $parse_count, 1, 'expected number of parses';
done_testing;
Unabiguous grammar:
Sequence : WORD+ SequenceAfterWords
| Group SequenceAfterGroup
SequenceAfterWords : Group SequenceAfterGroup
|
SequenceAfterGroup : WORD+ SequenceAfterWords
|
Jeffrey Kegler says that leading with the recursion is handled more efficiently in Marpa. The same approach taken above can be taken back to front to produce this.
Sequence : SequenceBeforeWords WORD+
| SequenceBeforeGroup Group
SequenceBeforeWords : SequenceBeforeGroup Group
|
SequenceBeforeGroup : SequenceBeforeWords WORD+
|
In both cases,
Group : GroupItem+
GroupItem : '[' Sequence ']'

How to get all options from Getopt Long without specifc knowledge of the params?

I need a simple script that echos ALL options and values given (and I have no idea what the potential options are going to be). I've experimented with things like this:
use Getopt::Long qw(GetOptionsFromArray);
my %options;
my #opt_spec = qw(a:s b:s c:s d:s e:s f:s g:s h:s i:s j:s k:s l:s m:s n:s o:s p:s r:s q:s r:s s:s t:s u:s v:s w:s x:s y:s z:s);
Getopt::Long::GetOptions(\%options, #opt_spec);
but I'm still having to specify all possible options - is there a way to get all the key/value pairs without knowing ahead of time what I'll be receiving as options?
Getopt::Long supports much more than just key-value pairs: negatable options, options with multiple or hash values, incrementing options, single character and bundled options. Without giving exact scheme Getopt::Long just can't guess what exact abilities of module you'd want to use, so it don't seems like it is the tool for this task.
You might want Getopt::Whatever instead.
You do need a spec. If you didn't have a spec, there would be no way to know that
-a=-b -c -d -e -f g --h -- -i -j
should give
my %options = (
'a' => '-b',
'c' => '',
'd' => '',
'e' => '',
'f' => 'g'
'h' => '',
);
#ARGV = (
'-i',
'-j',
);
instead of
my %options = (
'a' => '-b',
'c' => '-d',
'e' => '-f',
'h' => '--',
'i' => '-j'
);
#ARGV = (
'g',
);
(The latter used a=s, b=s, etc.)
You could write a version of GetOptions that gives the :s spec to all names, but as long as you only have single-letter args, it would be simpler to simple use code to generate the spec.
my #opt_spec = map "$_:s", 'a'..'z';

How can I split a Perl string only on the last occurrence of the separator?

my $str="1:2:3:4:5";
my ($a,$b)=split(':',$str,2);
In the above code I have used limit as 2 ,so $a will contain 1 and remaining elements will be in $b.
Like this I want the last element should be in one variable and the elements prior to the last element should be in another variable.
Example
$str = "1:2:3:4:5" ;
# $a should have "1:2:3:4" and $b should have "5"
$str = "2:3:4:5:3:2:5:5:3:2"
# $a should have "2:3:4:5:3:2:5:5:3" and $b should have "2"
split(/:([^:]+)$/, $str)
You could use pattern matching instead of split():
my ($a, $b) = $str =~ /(.*):(.*)/;
The first group captures everything up to the last occurence of ':' greedily, and the second group captures the rest.
In case the ':' is not present in the string, Perl is clever enough to detect that and fail the match without any backtracking.
you can also use rindex() eg
my $str="1:2:3:4:5";
$i=rindex($str,":");
$a=substr($str,0,$i);
$b=substr($str,$i+1);
print "\$a:$a, \$b: $b\n";
output
$ perl perl.pl
$a:1:2:3:4, $b: 5
I know, this question is 4 years old. But I found the answer from YOU very interesting as I didn't know split could work like that. So I want to expand it with an extract from the perldoc split that explains this behavior, for the sake of new readers. :-)
my $str = "1:2:3:4:5";
my ($a, $b) = split /:([^:]+)$/, $str;
# Capturing everything after ':' that is not ':' and until the end of the string
# Now $a = '1:2:3:4' and $b = '5';
From Perldoc:
If the PATTERN contains capturing groups, then for each separator, an additional field is produced for each substring captured by a group (in the order in which the groups are specified, as per backreferences); if any group does not match, then it captures the undef value instead of a substring. Also, note that any such additional field is produced whenever there is a separator (that is, whenever a split occurs), and such an additional field does not count towards the LIMIT. Consider the following expressions evaluated in list context (each returned list is provided in the associated comment):
split(/-|,/, "1-10,20", 3)
# ('1', '10', '20')
split(/(-|,)/, "1-10,20", 3)
# ('1', '-', '10', ',', '20')
split(/-|(,)/, "1-10,20", 3)
# ('1', undef, '10', ',', '20')
split(/(-)|,/, "1-10,20", 3)
# ('1', '-', '10', undef, '20')
split(/(-)|(,)/, "1-10,20", 3)
# ('1', '-', undef, '10', undef, ',', '20')
You can do it using split and reverse as follows:
my $str="1:2:3:4:5";
my ($a,$b)=split(':',reverse($str),2); # reverse and split.
$a = reverse($a); # reverse each piece.
$b = reverse($b);
($a,$b) = ($b,$a); # swap a and b
Now $a will be 1:2:3:4 and $b will be 5.
A much simpler and cleaner way is to use regex as Mark has done in his Answer.
I'm a bit late to this question, but I put together a more generic solution:
# Similar to split() except pattern is applied backwards from the end of the string
# The only exception is that the pattern must be a precompiled regex (i.e. qr/pattern/)
# Example:
# rsplit(qr/:/, 'John:Smith:123:ABC', 3) => ('John:Smith', '123', 'ABC')
sub rsplit {
my $pattern = shift(#_); # Precompiled regex pattern (i.e. qr/pattern/)
my $expr = shift(#_); # String to split
my $limit = shift(#_); # Number of chunks to split into
# 1) Reverse the input string
# 2) split() it
# 3) Reverse split()'s result array element order
# 4) Reverse each string within the result array
map { scalar reverse($_) } reverse split(/$pattern/, scalar reverse($expr), $limit);
}
It accepts arguments similar to split() except that the splitting is done in reverse order. It also accepts a limit clause in case you need a specified number of result elements.
Note: this subroutine expects a precompiled regex as the first parameter.
Perl's split is a built-in and will interpret /pat/ correctly, but attempting to pass /pat/ to a subroutine will be treated as sub($_ =~ /pat/).
This subroutine is not bulletproof! It works well enough for simple delimiters but more complicated patterns can cause issues. The pattern itself cannot be reversed, only the expression it matches against.
Examples:
rsplit(qr/:/, 'One:Two:Three', 2); # => ('One:Two', 'Three')
rsplit(qr/:+/, 'One:Two::Three:::Four', 3); # => ('One:Two', 'Three', 'Four')
# Discards leading blank elements just like split() discards trailing blanks
rsplit(qr/:/, ':::foo:bar:baz'); # => ('foo', 'bar', 'baz')