remove double quotes using a macro - libreoffice

I am using this function and it is working as expected. It removes all punctuation.
The first problem is that it does not remove double quotes "
The second problem is that I need to select text that needs to be processed. I will prefer that current file (all text) corrected by default.
Sub removePunc()
REM the text ranges to work on must be seleczed in advance.
REM This will be done mostly by a F&R action with an appropriate
REM search strung and 'Find All'.
REM the this macro can be run.
fa = createUnoService("com.sun.star.sheet.FunctionAccess")
rgs = ThisComponent.CurrentSelection
n = rgs.Count -1
For k = 0 To n
rg = rgs(k)
h = fa.callFunction("REGEX", Array(rg.String, "!", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "'", " ", "g"))
h = fa.callFunction("REGEX", Array(h , ",", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\(", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\)", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\*", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\-", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\;", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\?", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\[", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\]", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\–", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\—", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\‘", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\“", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\”", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\.", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\:", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\'", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\uFEFF", " ", "g"))
rg.String = h
Next k
End Sub

This works for me:
h = fa.callFunction("REGEX", Array(h, """", " ", "g"))
I know next to nothing about VBA and LibreOffice so probably this is not an optimal solution but it works somehow with no selection:
Sub removePunc()
fa = createUnoService("com.sun.star.sheet.FunctionAccess")
rg = ThisComponent.Text
h = fa.callFunction("REGEX", Array(rg.String, "!", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "'", " ", "g"))
h = fa.callFunction("REGEX", Array(h , ",", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\(", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\)", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\*", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\-", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\;", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\?", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\[", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\]", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\–", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\—", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\‘", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\“", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\”", " ", "g"))
h = fa.callFunction("REGEX", Array(h , "\.", " ", "g"))
h = fa.callFunction("REGEX", Array(h , """", " ", "g"))
ThisComponent.Text.String = h
End Sub
Actually all your changes can be done in one step:
Find for: "[!',\(\)\*\-;\?\[\]\–\—‘“”\.\""]"
Replace with: (space)
Nevertheless if you want to use a list of changes here is the more optimal implementation:
Sub Replace
Dim to_search() As String
Dim to_replace() As String
Dim n As Long
Dim oDocument As Object
Dim oReplace As Object
to_search() = Array("[!',\(\)\*\-;\?\[\]\–\—‘“”\.\""]")
to_replace() = Array(" ")
oDocument = ThisComponent
oReplace = oDocument.createReplaceDescriptor
oReplace.SearchRegularExpression = True
For n = lbound(to_search()) To ubound(to_search())
oReplace.SearchString = to_search(n)
oReplace.ReplaceString = to_replace(n)
oDocument.replaceAll(oReplace)
Next n
End Sub
Based on the official examples: https://api.libreoffice.org/examples/basic/text/modifying_text_automatically/
It does replacement in one step as well, but you can add to the arrays additional elements if you want, this way:
to_search() = Array("no", "never", "no way!")
to_replace() = Array("yes", "always", "why not?")

Thanks to the user #Yuri khristich this worked as expected:
Sub removePunc()
fa = createUnoService("com.sun.star.sheet.FunctionAccess")
rg = ThisComponent.Text
h = fa.callFunction("REGEX", Array(rg.String, "[!',\:\(\)\*\-;\?\[\]\–\—‘“”\.\""]", " ", "g"))
h = fa.callFunction("REGEX", Array(h, "\uFEFF", " ", "g"))
ThisComponent.Text.String = h
ListMisSpelledWords3
End Sub

Related

Rearrange print order of key-value data read from file in Perl

My data looks like:
"latDD":33.732867,
"lonDD":-84.404525,
"callsign":"AAL1300 ",
"timeStamp":"2019-07-19T13:47:49.46Z",
"latDD":33.732867,
"lonDD":-84.404525,
"callsign":"AAL1300 ",
"timeStamp":"2019-07-19T13:47:50.186Z",
"latDD":33.781071,
"lonDD":-84.401736,
"callsign":"GT017 ",
"timeStamp":"2019-07-19T13:47:50.0Z",
"latDD":33.781071,
"lonDD":-84.401736,
"callsign":"GT017 ",
"timeStamp":"2019-07-19T13:47:50.0Z",
"latDD":33.732867,
"lonDD":-84.401664,
"callsign":"AAL1300 ",
I want to print callsign first, then print the latDD that is before callsign second, then print the lonDD that is before callsign third,
then the timeStamp that is after callsign fourth.
the finished data should look like:
"callsign":"AAL1300 ",
"latDD":33.732867,
"lonDD":-84.404525,
"timeStamp":"2019-07-19T13:47:49.46Z",
"callsign":"AAL1300 ",
"latDD":33.732867,
"lonDD":-84.404525,
"timeStamp":"2019-07-19T13:47:50.186Z",
"callsign":"GT017 ",
"latDD":33.781071,
"lonDD":-84.401736,
"timeStamp":"2019-07-19T13:47:50.0Z",
"callsign":"GT017 ",
"latDD":33.781071,
"lonDD":-84.401736,
"timeStamp":"2019-07-19T13:47:50.0Z",
I've tried shifting the print statements around in the code but since the data is in a specific order, it seems to only want to print the data out in the order that it is originally in.
use strict;
my $find3 = "latDD";
my $find4 = "lonDD";
my $find1 = '"callsign"';
my $find2 = "timeStamp";
open (NEW1, ">", "new1.txt" ) or die "could not open:$!";
open (FILE, "<", "test revam.txt") or die "could not open:$!";
while (<FILE>) {
print NEW1 if (/$find1/);
print NEW1 if (/$find2/);
print NEW1 if (/$find3/);
print NEW1 if (/$find4/);
}
close (FILE);
close (NEW1);
while (1) {
defined( my $line1 = <> ) or last;
defined( my $line2 = <> ) or die;
defined( my $line3 = <> ) or die;
defined( my $line4 = <> ) or die;
print $line3, $line1, $line2, $line4;
}
You need to keep track of one set of your data (one of each of line) and then when you have a last line in the set (in this case timestamp) print them all in the order you prefer.
#!/usr/bin/perl
use strict;
my %vals; # hash to hold a set of lines
# read data (I'm using __DATA__, you probably want a file or stdin)
for my $line (<DATA>) {
my ($key) = $line =~ /"(.+?)"/; # parse the key out of the line
$vals{$key} = $line; # save the line for this key
if ($key eq 'timeStamp') { # are we done with this set of lines?
printBlock(); # print them
%vals = (); # clear the hash for the next set of lines
}
}
printBlock();
sub printBlock {
print '-'x50 . "\n"; # OPTIONAL print a line between each set
print $vals{callsign};
print $vals{latDD};
print $vals{lonDD};
print $vals{timeStamp};
}
__DATA__
"latDD":33.732867,
"lonDD":-84.404525,
"callsign":"AAL1300 ",
"timeStamp":"2019-07-19T13:47:49.46Z",
"latDD":33.732867,
"lonDD":-84.404525,
"callsign":"AAL1300 ",
"timeStamp":"2019-07-19T13:47:50.186Z",
"latDD":33.781071,
"lonDD":-84.401736,
"callsign":"GT017 ",
"timeStamp":"2019-07-19T13:47:50.0Z",
"latDD":33.781071,
"lonDD":-84.401736,
"callsign":"GT017 ",
"timeStamp":"2019-07-19T13:47:50.0Z",
"latDD":33.732867,
"lonDD":-84.401664,
"callsign":"AAL1300 "

Adding space to more symbols

i have this string for example
$string="put#returns-between|par/agra\phs"; // #-|/\
how to add space to each sympol with one command
this is result
$result :"put # returns - between | par / agra \ phs
i have used this solution but I would like to know if there is better than this
<?php
$string="put#returns-between|par/agra\phs"; // #-|/\
$str=preg_replace("/[#]/", " # ", $string);
$str=preg_replace("/[-]/", " - ", $str);
$str=preg_replace("/[|]/", " | ", $str);
$str=preg_replace("/[\/]/", " / ", $str);
thanks.
<?php
$string="put#returns-between|par/agra\phs"; // #-|/\
$str=preg_replace("/([#|\-|\||\\\\|\/])/", " $1 ", $string);
echo $str;
see the demo, hope it helps.
Use a character class:
$string = "put#returns-between|par/agra\phs";
$str = preg_replace("~([-#|\\\\/])~", " $1 ", $string);
echo $str;
Output:
put # returns - between | par / agra \ phs

Calculate difference of two values in hash

Input from file
ID S1 S2 S3 S4
a R1 R2 R3 R4 R5 R6 R7 R8
. . . . . .
. . . . .
a is the ID may be string
R1,R2,R3,R4.....are numeric values
I have to use perl script.I have to read the above data from a file and read in hashes.I have to calculate the difference of R1 and R2 if difference is greater than 0 then print R1 and R2 as it is,other put 0 in place of R1 and R2. next find the difference of R3 and R4. How can we do the above problem using hashes
Output of the perl program:
ID S1 S2 S3 S4
a R1 R2 0 0 0 0 R7 R8
. . . . . .
. . . . .
. . . . .
Why would you need a hash to find the difference of pairs of numbers???
print(scalar(<>));
while (<>) {
my #parts = split ' ';
for (my $i=1; $i<#parts; $i+=2) {
if ($parts[$i+0] == $parts[$i+1]) {
$parts[$i+0] = '0';
$parts[$i+1] = '0';
}
}
print(join(' ', #parts), "\n");
}
Or if you want to preserve the formatting:
print(scalar(<>));
while (<>) {
chomp;
my #parts = split /(\s+)/;
for (my $i=2; $i<#parts; $i+=4) {
if ($parts[$i+0] == $parts[$i+2]) {
$parts[$i+0] = sprintf('%*s', length($parts[$i+0]), '0');
$parts[$i+2] = sprintf('%*s', -length($parts[$i+2]), '0');
}
}
print(join('', #parts), "\n");
}

Perl - lookahead assertion

I'm trying to describe a perl script for this purpose:
a = ~b & ~c; ==> a = (~b) & (~c);
a = ~b & (~c); ==> a = (~b) & (~c);
So I used lookahead assertions to insert parenthesis like this. Here is the test code.
#!/usr/local/bin/perl5 -w
use strict;
use warnings;
my $line;
my #lines;
#lines = (
"assign a = ~b & ~c;",
"assign a = (~b) & (~c);",
"assign a = ( ~b & ~c );",
"assign a = (b & ~c );"
);
foreach $line (#lines) {
print " $line\n";
$line =~ s/(?!\(\s*)~\w+(?!\s*\))/\($&\)/g;
print ">> $line\n\n";
}
It looks working with above examples. However, it's not working with this.
assign a = ~b & ~c;
>> assign a = (~b) & (~c); <== OK
assign a = (~b) & (~c);
>> assign a = (~b) & (~c); <== OK
assign a = ( ~b & ~c);
>> assign a = ( (~b) & ~c); <== X. I want ( (~b) & (~c));
assign a = ( ~b & ~c );
>> assign a = ( (~b) & ~c ); <== X. I want ( (~b) & (~c) );
Would you let me know how to fix the script? Thank you.
Your goal of using lookahead and lookbehind assertions doesn't really get you anything. Breaking up the code into two steps makes it easier in my opinion. One step to capture variables prefixed by ~, and the second part to see if they're surrounded by balanced parenthesis.
use strict;
use warnings;
while (<DATA>) {
chomp(my $src = <DATA>);
chomp(my $test = <DATA>);
$src =~ s{([(]?~\w+[)]?)}{
my $str = $1;
$str =~ /^\(.*\)$/ ? $str : "($str)";
}eg;
print "test $test\n";
print $src eq $test ? ' ok ' : ' FAIL! ';
print "$src\n";
}
__DATA__
Test:
a = ~b & ~c;
a = (~b) & (~c);
Test:
a = (~b) & (~c);
a = (~b) & (~c);
Test:
a = ( ~b & ~c);
a = ( (~b) & (~c));
Test:
a = ( ~b & ~c );
a = ( (~b) & (~c) );
results:
test a = (~b) & (~c);
ok a = (~b) & (~c);
test a = (~b) & (~c);
ok a = (~b) & (~c);
test a = ( (~b) & (~c));
ok a = ( (~b) & (~c));
test a = ( (~b) & (~c) );
ok a = ( (~b) & (~c) );
You can't easily do what you're asking using a single regular expression.
The problem is that there is no way to count the number of nested parentheses without writing a recursive regex pattern, so at the end of ~c simple regex cannot know whether how many parentheses are needed to close the expression.
This is possible with a more complex regex, but it would also be much easier to tokenize the string in a Perl loop.
Do you have to deal with stuff like a & ~b & c | (d | ~e & f)?
You can do this with one regex, here it is;
$line =~ s/(?|([^\(])(~\w+)(.)|(.)(~\w+)([^\)]))/$1\($2\)$3/g;
Your reqex wasn't doing what you thought.
$line =~ s/(?!\(\s*)~\w+(?!\s*\))/\($&\)/g;
the first part "(?!(\s*)~" will never match. Remember lookaheads and lookbehinds are zero width assertions. I like to think of them as matching the space in between the letters. (?!(\s*)~ means, that you want to match a "~" character, but in the space right before the "~"character, you want to lookahead and make sure you dont see a "(" and spaces. Well, if you are in the space right before a "~", you"ll never see a "(". And if your at a "(", the negative look ahead might fail to match (like you want) but you'd have never matched the "~" anyway.
You are trying to match if the character before is not a "(" AND the char after is not a ")". But what you want is to match if the character before is not a "(" OR the char after is not a ")". So you need a conditional branch, one to match if there is no "(" in front, and one to match if there is no ")" behind.
I used a condition branch, the (?| tells the engine to store the captured submatches like this;
(?|([^\\(])(~\w+)(.)|(.)(~\w+)([^\\)]))
$1 $2 $3 |$1 $2 $3
instead of this
([^\\(])(~\w+)(.)|(.)(~\w+)([^\\)]))
$1 $2 $3 |$4 $5 $6
I used (.) to make the ~\w part always $2, then just put a "(" ")" around the $2 in the output
my output
assign a = ~b & ~c;
assign a = (~b) & (~c);
assign a = (~b) & (~c);
assign a = (~b) & (~c);
assign a = ( ~b & ~c );
assign a = ( (~b) & (~c) );
assign a = (~b & ~c );
assign a = ((~b) & (~c) );
assign a = ( ~b & ~c );
assign a = ( (~b) & (~c) );
assign a = ( ~b & ~c);
assign a = ( (~b) & (~c));

FileMaker calculation to convert DMS latlong to decimal format

I need a FileMaker "calculation" script to convert a DMS latlong (eg: 37°55'43.6"S, 145°11'26.1"E) to a decimal format (eg: -37.928778,145.190583).
Here's a fun way to do it: convert it to a FileMaker calculation and call Evaluate() on it.
Evaluate(
"Round( (" &
Substitute (
dms ;
[" ";""] ;
["°";" + "] ;
["'";"/60 + "] ;
["\"";"/3600"] ;
["S";") *-1"] ;
["W";") *-1"] ;
["N";")"] ;
["E";")"] ;
[","; " ; 6 ) & \",\" & Round( ("]
) &
" ; 6 )"
)
The above will turn the input into a calc like:
Round( (37 + 55/60 + 43.6/3600) *-1 ; 6 ) & "," & Round( (145 + 11/60 + 26.1/3600) ; 6 )
then passes that to Evaluate, which gives you -37.928778,145.190583
Here is one that uses the split() custom function by David Snyder:
If ( IsEmpty(DMSLatlong);"";
"-" &
Truncate(
(
Trim(split(
Trim(split( DMSLatlong; 1; "," ))
; 1; "°" ))
) +
(
(
Trim(split(
Trim(split(
Trim(split( DMSLatlong; 1; "," ))
; 1; "'" ))
; 2; "°" ))
) / 60
) +
(
(
Trim(split(
Trim(split(
Trim(split( DMSLatlong; 1; "," ))
; 2; "'" ))
; 1; "\"" ))
) / 3600
)
;7)
& "," &
Truncate(
(
Trim(split(
Trim(split( DMSLatlong; 2; "," ))
; 1; "°" ))
) +
(
(
Trim(split(
Trim(split(
Trim(split( DMSLatlong; 2; "," ))
; 1; "'" ))
; 2; "°" ))
) / 60
) +
(
(
Trim(split(
Trim(split(
Trim(split( DMSLatlong; 2; "," ))
; 2; "'" ))
; 1; "\"" ))
) / 3600
)
;7)
)
Note: This script isn't bullet proof, and if DMS values are S or W, you may need to tweak it to put a - sign in front (as I have done above). Refer to: Wikipedia: Conversion from Decimal Degree to DMS.
It could be as simple as =
Let ( [
v = Substitute ( DMS ; [ "°" ; ¶ ] ; [ "'" ; ¶ ] ; [ "\"" ; ¶ ] ) ;
t = Time ( GetValue ( v ; 1 ) ; GetValue ( v ; 2 ) ; GetValue ( v ; 3 ) ) ;
h = GetValue ( v ; 4 )
] ;
If ( h = "S" or h = "W" ; -t ; t ) / 3600
)