Reputation: 2589
My Input *INI
file:
\nleftarrow = {\not\leftarrow}
\nrightarrow = {\not\rightarrow}
\nleftrightarrow = {\not\leftrightarrow}
I need to find the \not\leftarrow
and replace with the string \nleftarrow
. The things is here \not\leftarrow
we need to check whether the space is available in the finding string eg: \not \leftarrow
. Both the things we need to replace the string.
In Main file:
$str=~s/\\not\\leftarrow/\\nleftarrow/g;
$str=~s/\\not \\leftarrow/\\nleftarrow/g;
My Code:
foreach my $repStr(@tags) #storing all the `*INI` lines in the Array
{
my ($findStr, $replaceStr) = ($repStr =~ /^([^\s]*)\s*=\s*\{([^\{\}]*)\}/i);
$str=~s/$replaceStr/$findStr/g;
#I need to check the string with space
}
Could anyone can guide me the way to code the request.
Upvotes: 0
Views: 613
Reputation: 118148
To fix ideas, the following are given:
This maps TeX/LaTeX macro names to sequences of TeX/LaTeX commands. It is in macro name = command sequence
format. E.g.:
\nleftarrow = {\not\leftarrow}
\nrightarrow = {\not\rightarrow}
\nleftrightarrow = {\not\leftrightarrow}
It is not clear what function is served by the braces which enclose the replacements. Do they appear in the source file (see below)? Or, do they delimit whitespace? In short, are they supposed to be stripped?
It would have been much better if you had provided just a paragraph of sample text instead of requiring us to make assumptions about it.
In this, there are command sequences which need to be replaced with macro names based on the mapping in the configuration file mentioned above. However, because TeX eats spaces after macro invocations, one needs to consider the possibility of a space character in between every command in the replacement sequence. In the example above, there are only two commands in each replacement sequence, but it is not hard to imagine more.
It would have been much better if you had provided just a paragraph of sample text instead of requiring us to construct it.
You seem to have cooked up a custom way of parsing the mapping of replacements. I would recommend using a decent parser instead, e.g. Config::INI::Reader.
#!/usr/bin/env perl
use strict;
use warnings;
use Config::INI::Reader;
my $ini_contents = <<'EO_INI';
\nleftarrow = {\not\leftarrow}
\nrightarrow = {\not\rightarrow}
\nleftrightarrow = {\not\leftrightarrow}
EO_INI
my $tex_source = <<'EO_TEX';
Lorem ipsum dolor \not\leftarrow{} sit amet, ea quem idque senserit eum, in
\not \rightarrow{} duo amet recusabo sensibus. Mei velit suavitate ei, ferri
consequuntur vis eu, qui unum volumus an. Rebum democritum no nec, et \not
\leftrightarrow{} eam natum patrioque, mentitum evertitur reprimique nec te.
Usu et docendi \not\rightarrow{} partiendo, eos ut assum errem simul.
EO_TEX
# Helper function to deal with matches with spaces
# because our mapping does not have sequences
# containing spaces.
sub match_to_key {
my ($s) = @_;
$s =~ s/\s+//g;
return $s;
}
# Assume mappings appear in a single global section only
my $macro_definition = Config::INI::Reader->read_string($ini_contents)->{_};
# Assuming { and } need to be removed
for (values %$macro_definition) {
s/^\{//;
s/\}\z//;
}
# map command sequences to replacement macros
$macro_definition = { reverse %$macro_definition };
my $command_sequence_pat = join '|',
sort { length($b) <=> length($a) }
map join('\s?', map quotemeta, m{ (\\\w+) }gx),
keys %$macro_definition
;
print "Text before replacement:\n";
print ">>>$tex_source<<<\n\n";
$tex_source =~ s/($command_sequence_pat)/$macro_definition->{match_to_key($1)}/g;
print "Text after replacement:\n";
print ">>>$tex_source<<<\n\n";
Note that the wrapping of original text might get messed up.
Output:
Text before replacement:
>>>Lorem ipsum dolor \not\leftarrow{} sit amet, ea quem idque senserit eum, in
\not \rightarrow{} duo amet recusabo sensibus. Mei velit suavitate ei, ferri
consequuntur vis eu, qui unum volumus an. Rebum democritum no nec, et \not
\leftrightarrow{} eam natum patrioque, mentitum evertitur reprimique nec te.
Usu et docendi \not\rightarrow{} partiendo, eos ut assum errem simul.
<<<
Text after replacement:
>>>Lorem ipsum dolor \nleftarrow{} sit amet, ea quem idque senserit eum, in
\nrightarrow{} duo amet recusabo sensibus. Mei velit suavitate ei, ferri
consequuntur vis eu, qui unum volumus an. Rebum democritum no nec, et \nleftrightarrow{} eam natum patrioque, mentitum evertitur reprimique nec te.
Usu et docendi \nrightarrow{} partiendo, eos ut assum errem simul.
<<<
Upvotes: 1
Reputation: 6626
You can create an array of single commands from your combination of commands: my @cmds = $replaceStr =~ /\\[^\\]+/g
. And then join them with optional spaces in between: join '\s*', @cmds
.
However, you also need to escape the special characters of $replaceStr
(like the backslashes) or they will bother you in the regex. You can do that with the quotemeta
built-in. (This can also be done from inside the regex with \Q...\E
, but since here you won't want the \s*
to be escaped, quotemeta
will be more convenient).
Put together, it becomes:
my @cmds = $replaceStr =~ /\\[^\\]+/g
my @esc_cmds = map { quotemeta } @cmds;
my $re = join '\s*', @esc_cmds;
But you can combine it in a single line (if it's readable enough for you):
my $re = join '\s*', map { quotemeta } ($replaceStr =~ /\\[^\\]+/g);
For instance, this script works the way you want:
use strict;
use warnings;
use feature 'say';
my @tags = ( '\nleftarrow = {\not\leftarrow}',
'\nrightarrow = {\not\rightarrow}',
'\nleftrightarrow = {\not\leftrightarrow}' );
# Only the last 2 lines should be left unchanged
my $str = '\not\leftarrow
\not \leftarrow
\not\leftarrow
\ not\leftarrow
\leftarrow';
say "Before:\n$str";
foreach my $repStr(@tags) {
my ($findStr, $replaceStr) = ($repStr =~ /^([^\s]*)\s*=\s*\{([^\{\}]*)\}/i);
my $re = join '\s*', map { quotemeta } ($replaceStr =~ /\\[^\\]+/g);
$str =~ s/$re/$findStr/g;
}
say "\nAfter:\n$str";
Upvotes: 1