Need some help with multiple search-replace Apple script

114 views
Skip to first unread message

Mathias af Jochnick

unread,
Oct 13, 2020, 8:12:33 AM10/13/20
to BBEdit Talk
Hi there,
i'm trying to make 2 scripts to convert between IOS and Android i18n formats to work. I've gotten Android -> IOS to work, but the other way around is a challenge.

Basically, for each row in a file i want to convert
"login_infoLabel" = "Do you need help? Press here.”;
to
<string name="login_infoLabel">Do you need help? Press here.</string

See my script below. The problem is the first search string to find the first " on each row. I spoke with Patrik at BBEdit and he kindly informed me that it was because AppleScript doesn't support grep and that i should instead record my replace with the script editor. 

I did that, but now i'm at a loss as to how combine these two snippets, where one is apple script and one is not?

Also, the 'record' contains the actual file name, how do i make the script just use the file showing in the window as i do with the apple script?

If anyone could point me in the right direction, i'd be most thankful.


My replace "recording":
replace "^\"" using "<string name=\\\"" searching in text 1 of text document "untitled text 133" options {search mode:grep, starting at top:true}


My Apple script (the first item in search_strings is what won't work):
set search_strings to {"^\"", "\" = \"", "\";"}
set replace_strings to {"<string name=\"", "\">", "</string>"}

tell application "BBEdit"
set the_string to (selection of front window as string)
repeat with i from 1 to (count search_strings)
set the_string to my snr(the_string, item i of search_strings, item i of replace_strings)
end repeat
--set the clipboard to the_string
set selection of front window to the_string
end tell

on snr(the_string, search_string, replace_string)
tell (a reference to my text item delimiters)
set {old_atid, contents} to {contents, search_string}
set {the_string, contents} to {the_string's text items, replace_string}
set {the_string, contents} to {"" & the_string, old_atid}
end tell
return the_string
end snr

The 'record' from BBEdit:

jj

unread,
Oct 13, 2020, 2:41:53 PM10/13/20
to BBEdit Talk
Mathias,

It would be way simpler to just use the "Find and Replace" window using the below regular expressions and replacement strings.

In the find window check the "Grep" and  "Wrap around" checkboxes and leave the other checkboxes unchecked.

If it works for your purpose in the "Find" window, you can then automate the process with a "Replace All" text factory: File menu > New > Text Factory.

From double quotes -> tags:

Find:

^\h*["”]((?:[^"”\\]|\\.)+?)["”]\h*=\h*["”]([^"”]+)[”"]\h*;\h*$

Replace:

<string name="\1">\2</string>


From tags -> double quotes:

Find:

^\h*<string\h+name\h*=\h*[”"]((?:[^"”\\]|\\.)+?)[”"]>([^<]+)</string>\h*$

Replace:

"\1" = "\2";

The regular expressions are a bit complicated because they handle the different type of quotations marks used in your example and the case of escaped quotes in the strings.

If you have escaped quotes (\") in your strings, think to convert them to html entities (&quot;) in your tag version.

HTH

Jean Jourdain

John Delacour

unread,
Oct 15, 2020, 9:26:55 AM10/15/20
to bbe...@googlegroups.com


On 13 Oct 2020, at 06:54, Mathias af Jochnick <mat...@lightlabs.se> wrote:

i'm trying to make 2 scripts to convert between IOS and Android i18n formats to work. I've gotten Android -> IOS to work, but the other way around is a challenge.

Basically, for each row in a file i want to convert
"login_infoLabel" = "Do you need help? Press here.”;
to
<string name="login_infoLabel">Do you need help? Press here.</string

See my script below. The problem is the first search string to find the first " on each row. I spoke with Patrik at BBEdit and he kindly informed me that it was because AppleScript doesn't support grep

Patrick could not be more right!  AppleScript is not the tool for text; but BBEdit provides the Text Factory feature that allows you to use Perl (or Python, or sed) to do the work easily.

Here is your script written in Perl:

#! /usr/bin/perl
while (<>) {
# changes quotes round string name to §, preserving them
s~"(login_infoLabel)" ?= ?([^;]+);~<string name=§$1§>$2</string>~g;
# delete the quotes not preserved
s~"~~g;
# restore the quotes round string name
s~§~"~g;
# remove the final semicolon
s~;$~~;
# Execute the substitutions
print;
}

This script will operate on the front window.

How to do it
1. Open a new Text Factory (Menu: File::New...), paste in the above script, and save it as test.pl in
~/Library/Application Support/BBEdit/Text Filters/
2. Open the (Menu: Window::Palettes::)Text Filters palette
3. Set a shortcut of you like
4. Run the script (filter) with your target window frontmost.

Notes—
I use "~" in the regex rather than "/".  You can use whatever you like.
s~found~replacement~g ;  #~g means replace all
Perl Regular Expressions differ from BBEdit's PRE in using $1, $2 etc rather than \1, \2
All the Perl knowledge you need to make the filter is:
a valid shebang line (should not be necessary and was not in better days!);
the while loop: while (<>) { ...... } ;
a knowledge of regex in Perl, which is almost the same as BBEdit's implementation but more powerful.

JD





Mathias

unread,
Oct 29, 2020, 8:48:43 AM10/29/20
to BBEdit Talk
Guys, thanks a bunch for great feedback! I will take your stuff and make it work i'm sure. If not i'll bother you here again! :) The reason for me taking AppleScript is that i was doing stuff before i had BBEdit and i kinda knew it, that's all.

Mathias

unread,
Dec 14, 2020, 8:38:19 AM12/14/20
to BBEdit Talk
Hi, work is crazy, so believe it or not, with all else going on as you know, I haven't had time to look at this until now.. Checking the Perl script, i have one question - (since my perl knowledge is very limited). Isn't the script expecting every row to begin with "login_infolabel" as it is written right now? The variable names in the files are different on every row. Or am i missing something obvious? Cheers

Christopher Stone

unread,
Dec 14, 2020, 5:35:57 PM12/14/20
to BBEdit-Talk
On 12/14/2020, at 07:38, Mathias <mat...@lightlabs.se> wrote:
… Isn't the script expecting every row to begin with "login_infolabel" as it is written right now? The variable names in the files are different on every row. Or am i missing something obvious?


Hey Mathias,

Please provide a more complete set of before and after examples.

--
Best Regards,
Chris

Mathias

unread,
Dec 15, 2020, 1:42:19 AM12/15/20
to BBEdit Talk
Hi Chris, sure!

Below are three example rows the way they work on Android, followed by their equivalent IOS counterparts.

<string name="switch_header">Switch account</string>
<string name="automaticCheckinTo">Automatic check-in to %1$s</string>
<string name="shortcut_subtitle_checkin">Choose location</string>


"switch_header" = "Switch account";
"automaticCheckinTo" = "Automatic check-in to %@";
"shortcut_subtitle_checkin" = "Choose location";

Christopher Stone

unread,
Dec 17, 2020, 2:08:58 AM12/17/20
to BBEdit-Talk
On 12/15/2020, at 00:42, Mathias <mat...@lightlabs.se> wrote:
Below are three example rows the way they work on Android, followed by their equivalent IOS counterparts.

<string name="switch_header">Switch account</string>
<string name="automaticCheckinTo">Automatic check-in to %1$s</string>
<string name="shortcut_subtitle_checkin">Choose location</string>


"switch_header" = "Switch account";
"automaticCheckinTo" = "Automatic check-in to %@";
"shortcut_subtitle_checkin" = "Choose location";


Hey Mathias,

Okay, that helps.

Let's start with AppleScript, since that's the way you began yourself.

--------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2020/12/17 00:01
# dMod: 2020/12/17 00:01 
# Appl: BBEdit
# Task: Android Strings to Equivalent iOS Strings.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @BBEdit, @Android, @IOS, @RegEx
--------------------------------------------------------

tell application "BBEdit"
    tell front text window

        

        replace "<string name=(\"[^\"]+?\")>([^<]+?)</string>" using "\\1 = \"\\2\";" options ¬
            {search mode:grep, case sensitive:false, starting at top:true}
        replace "%1$s" using "%@" options {case sensitive:false, starting at top:true}

        

    end tell
end tell

--------------------------------------------------------


--------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2020/12/17 00:01
# dMod: 2020/12/17 00:03
# Appl: BBEdit
# Task: iOS Strings to Equivalent Android Strings.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @BBEdit, @Android, @IOS, @RegEx
--------------------------------------------------------

tell application "BBEdit"
    tell front text window

        

        replace "(\"[^\"]+?\") = \"([^\"]+?)\";" using "<string name=\\1>\\2</string>" options ¬
            {search mode:grep, case sensitive:false, starting at top:true} -- RegEx replacement.
        replace "%@" using "%1$s" options {case sensitive:false, starting at top:true} -- Literal replacement.

        

    end tell
end tell

--------------------------------------------------------


Now let's attempt some Perl:


#!/usr/bin/env perl -0777 -nw
# --------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2020/12/17 00:20
# dMod: 2020/12/17 00:21
# Task: Android Strings to Equivalent iOS Strings.
# Tags: @ccstone, @Shell, @Script, @Android, @iOS, @Perl
# --------------------------------------------------------

s!<string name=("[^"]+?")>([^<]+?)</string>!$1 = "$2";!ig;
s!%1\$s!%@!ig;

print;

# --------------------------------------------------------


#!/usr/bin/env perl -0777 -nw
# --------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2020/12/17 00:20
# dMod: 2020/12/17 00:28
# Task: iOS Strings to Equivalent Android Strings.
# Tags: @ccstone, @Shell, @Script, @Android, @iOS, @Perl
# --------------------------------------------------------

s!("[^"]+?") = "([^"]+?)";!<string name=$1>$2</string>!ig;
s!%@!%1\$s!ig;

print;

# --------------------------------------------------------

In this case I'm scarfing up the whole file before doing the search/replace.  If the file was really big I'd iterate through the lines in a while loop.

Now for giggles let's trot out sed:

#!/usr/bin/env bash
# --------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2012/11/27 08:12
# dMod: 2020/12/17 01:05
# Task: Android Strings to Equivalent iOS Strings.
# Tags: @ccstone, @Shell, @Script, @Android, @iOS, @sed
# --------------------------------------------------------

sed -En '

   s!<string name=("[^"]+")>([^<]+)</string>!\1 = "\2";!
   s!%1\$s!%@!
   p

   

'

# --------------------------------------------------------


#!/usr/bin/env bash
# --------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2012/11/27 08:12
# dMod: 2020/12/17 00:53 
# Task: iOS Strings to Equivalent Android Strings.
# Tags: @ccstone, @Shell, @Script, @Android, @iOS, @sed
# --------------------------------------------------------

sed -En '

   s!("[^"]+") = "([^"]+)";!<string name=\1>\2</string>!
   s!%@!%1$s!
   p

   

'

# --------------------------------------------------------


Let me know if you have any problems.

--
Best Regards,
Chris

Reply all
Reply to author
Forward
0 new messages