Applescript and "starts with" operator - list

Is there a way to check (in applescript) if a list (or block of html text) starts with any number of values.
Example (checking for a single value)
if {foobar starts with "<p>"} then
-- do something awesome here
end if
except i would like to pass multiple values to check <p> or <h1> or <em>.
Thanks in advance.

on startswith(txt, l)
repeat with v in l
if txt starts with v then return true
end repeat
false
end startswith
startswith("abc", {"a", "d", "e"}) -- true

If you want to stay within the 'English' style of AppleScript, although longer than the example above, you can just do this:
if {foobar starts with "hello" or foobar starts with "goodbye"} then
A full example would be:
set foobar to "hello dude"
if {foobar starts with "hello" or foobar starts with "goodbye"} then
display dialog "found"
end if
That will be true even if you change:
set foobar to "hello dude"
to:
set foobar to "goodbye dude"

Related

Regex match text followed by curly brackets

I have a text like this:
"entity"
{
"id" "5040044"
"classname" "weapon_defibrillator_spawn"
"angles" "0 0 0"
"body" "0"
"disableshadows" "0"
"skin" "0"
"solid" "6"
"spawnflags" "3"
"origin" "449.47 5797.25 2856"
editor
{
"color" "0 0 200"
"visgroupshown" "1"
"visgroupautoshown" "1"
"logicalpos" "[-13268 14500]"
}
}
What would regex expression be to select only that part in Notepad++:
editor
{
"color" "0 0 200"
"visgroupshown" "1"
"visgroupautoshown" "1"
"logicalpos" "[-13268 14500]"
}
First word is always "editor", but the number of lines and content in curly brackets may vary.
editor\s*{\s*(?:\"[a-z]*\"\s*\".*\"\s*)*\}
Demo
Also tested it in Notepad++ it works fine
The simplest way to find everything between curly brackets would be \{[^{}]*\} (example 1).
You can prepend editor\s* on it so it limits the search to only that specific entry: editor\s*\{[^{}]*\} (example 2).
However... if any of the keys or value strings within editor {...} contain a { or }, you're going to have edge cases.
You'll need to find double-quoted values and essentially ignore them. This example shows how you would stop before the first double quote within the group, and this example shows how to match up through the first key-value pair.
You essentially want to repeatedly match those key-value pairs until no more remain.
If your keys or values can contain \" within them, such as "help" "this is \"quoted\" text", you need to look for that \ character as well.
If there are nested groups within this group, you'll need to recursively handle those. Most regex (Notepad++ included) don't handle recursion, though, so to get around this, you copy-paste what you have so far inside of the code if it happens to come across more nested { and }. This does not handle more than one level of nesting, though.
TL;DR
For Notepad++, this is a single line regex you could use.

AppleScript "if contain"

I have a script which look for the name and search for a match with a another variable.
It's working fine however if the variable 1 is "Name Demo" and variable 2 is "Demo Name" then the script don't find a match.
set nameMatchTXT to ""
if NameOnDevice contains theName then
set nameMatch to theName & " : Name Match"
end if
Is there anyway to change this to find the match whatever the order ?
PS the script is looking for word wild name, and sometime handle dual bit characters which can be a difficulty.
Your request stated:
if the variable 1 is "Name Demo" and variable 2 is "Demo Name" then
the script don't find a match.
This will solve that problem:
set var1 to "Name Demo"
set var2 to "Demo Name"
if (var2 contains (word 1 of var1)) and (var2 contains (word 2 of var1)) then
-- you have a match
display dialog "var1 and var2 match"
else
display dialog "no match"
end if
You will have to have make a separate check for each condition. There are other ways to do it (such as a complex regex), but this is the easiest and most readable.
set nameMatch1 to "Name"
set nameMatch2 to "Demo"
if (NameOnDevice contains nameMatch1) and (NameOnDevice contains nameMatch2) then
set nameMatch to NameOnDevice & " : Name Match"
end if
If you are adding matching criteria, you may eventually add more. Instead of adding more variables, and more conditions, you may want to put all of your words in a list and check against that. In the future, if you need to add more words, you can simply add the word to the list. I've extracted it into a separate sub-routine here for easier reading:
on name_matches(nameOnDevice)
set match_words to {"Name", "Demo"}
repeat with i from 1 to (count match_words)
if nameOnDevice does not contain item i of match_words then
return false
end if
end repeat
return true
end name_matches
if name_matches(nameOnDevice) then
set nameMatch to nameOnDevice & " : Name Match"
end if
Edit after clarification
If you have no control over the matching text (if it comes from an outside source, and is not coded by you), you can split that text into words and use those as the wordlist in the second example. For instance:
on name_matches(nameOnDevice, match_text)
set match_words to words of match_text
repeat with i from 1 to (count match_words)
if nameOnDevice does not contain item i of match_words then
return false
end if
end repeat
return true
end name_matches
if name_matches(nameOnDevice, match_text_from_some_other_source) then
set nameMatch to nameOnDevice & " : Name Match"
end if

In Vim, is there a "matching braces/parenthesis/etc" equivalent in substitute/search symbols?

I would like to replace for instance every occurrence of "foo{...}" with anything except newlines inside the bracket (there may be spaces, other brackets opened AND closed, etc) NOT followed by "bar".
For instance, the "foo{{ }}" in "foo{{ }}, bar" would match but not "foo{hello{}}bar".
I've tried /foo{.*}\(bar\)\#! and /foo{.\{-}}\(bar\)\#! but the first one would match "foo{}bar{}" and the second would match "foo{{}}bar" (only the "foo{{}" part).
this regex:
foo{.*}\([}]*bar\)\#!
matches:
foo{{ }}
foo{{ }}, bar
but not:
foo{hello{}}bar
It is impossible to correctly match an arbitrary level of nested
parentheses using regular expressions. However, it is possible to
construct a regex to match supporting a limited amount of nesting (I
think this answer did not attempt to do so). – Ben
This does ...
for up to one level of inner braces:
/foo{[^{}]*\({[^{}]*}[^{}]*\)*}\(bar\)\#!
for up to two levels of inner braces:
/foo{[^{}]*\({[^{}]*\({[^{}]*}[^{}]*\)*}[^{}]*\)*}\(bar\)\#!
for up to three levels of inner braces:
/foo{[^{}]*\({[^{}]*\({[^{}]*\({[^{}]*}[^{}]*\)*}[^{}]*\)*}[^{}]*\)*}\(bar\)\#!
...
Depends on what replacement you want to perform exactly, you might be able to do that with macros.
For example: Given this text
line 1 -- -- -- -- array[a][b[1]]
line 2 -- array[c][d]
line 3 -- -- -- -- -- -- -- array[e[0]][f] + array[g[0]][h[0]]
replace array[A][B] with get(A, B).
To do that:
Position the cursor at the begin of the text
/array<cr>
qq to begin recording a macro
Do something to change the data independent of the content inside (use % to go to matching bracket, and some register/mark/plugin to delete around the bracket). For example cwget(<esc>ldi[vhpa, <esc>ldi[vhpa)<esc>n -- but macros are usually unreadable.
n to go to next match, q to stop recording
#q repeatedly (## can be used from the second time)
This is probably not very convenient because it's easy to make a mistake (press I, <home>, A for example) and you have to redo the macro from the beginning, but it works.
Alternatively, you can do something similar to eregex.vim plugin to extend vim's regex format to support this (so you don't have to retype the huge regex every time).
Proof of concept:
"does not handle different magic levels
"does not handle '\/' or different characters for substitution ('s#a#b#')
"does not handle brackets inside strings
" usage: `:M/pattern, use \zm for matching block/replacement/flags`
command -range -nargs=* M :call SubstituteWithMatching(<q-args>, <line1>, <line2>)
":M/ inspired from eregex.vim
function SubstituteWithMatching(command, line1, line2)
let EscapeRegex={pattern->escape(pattern, '[]\')}
let openbracket ='([{'
let closebracket=')]}'
let nonbracketR='[^'.EscapeRegex(openbracket.closebracket).']'
let nonbracketsR=nonbracketR.'*'
let LiftLevel={pattern->
\nonbracketsR
\.'\%('
\.'['.EscapeRegex(openbracket).']'
\.pattern
\.'['.EscapeRegex(closebracket).']'
\.nonbracketsR
\.'\)*'
\}
let matchingR=LiftLevel(LiftLevel(LiftLevel(nonbracketsR)))
if v:false " optional test suite
echo "return 0:"
echo match('abc', '^'.matchingR.'$')
echo match('abc(ab)de', '^'.matchingR.'$')
echo match('abc(ab)d(e)f', '^'.matchingR.'$')
echo match('abc(a[x]b)d(e)f', '^'.matchingR.'$')
echo match('abc(a]b', '^'.matchingR.'$')
"current flaw (not a problem if there's only one type of bracket, or if
"the code is well-formed)
echo "return -1:"
echo match('abc(a(b', '^'.matchingR.'$')
echo match('abc)a(b', '^'.matchingR.'$')
endif
let [pattern, replacement, flags]=split(a:command, "/")
let pattern=substitute(pattern, '\\zm', EscapeRegex(matchingR), 'g')
execute a:line1.','.a:line2.'s/'.pattern.'/'.replacement.'/'.flags
endfunction
After this, :'<,'>M/array\[\(\zm\)\]\[\(\zm\)\]/get(\1, \2)/g can be used to do the same task above (after selecting the text in visual mode)

VB Script if statement: Sub not defined

I have the code below
if (LCase(Config_(C_))) like "show*" Then
crt.screen.send Config_(C_) & VBCR
crt.screen.WaitForStrings ">", "#"
End If
but when I run it I get a "Sub not defined on line 36 (which is the "if(LCase(....." line)
Config_ is an array of strings
C_ is the element address
So all I want to do is say,
If this array element starts with "show" then run the command, insuring it does not matter if the user emters upper or lower case.
Why this code does not work? Other if like statements seem ok.
As far as I'm aware, there's no like statement in vbscript. You could use Left which will return n number of characters at the start of a string and see if the string it return equals "show" -
if Left(LCase(Config_(C_)),4) = "show" Then
The work "LIKE" is not a key word or a function in vbscript

How can I replace the same string several times with different random values in Perl?

I'm using this Perl one-liner (in bash) to successfully replace a string with a random one, in a given file:
perl -pi -e "s/replace\ this/`</dev/urandom tr -dc A-Za-z0-9 | head -c64`/g" example.php
However, I don't know how to replace several "replace this" with different random strings.
perl -pi -e 's/replace this/join "", map { ("a" .. "z", "A" .. "Z", 0 .. 9)[rand(62)] } 1 .. 64/eg' example.php
Let's break this down into its pieces.
("a" .. "z", "A" .. "Z", 0 .. 9)
is a list that contains the characters you want to be in the random string.
[rand(62)]
This is indexing the list above at a random location (using the rand function). The 62 corresponds to the number of items in the list. The rand function returns a number between zero and the number you gave it minus one. Happily, arrays and lists are indexed starting at zero in Perl 5, so this works out perfectly. So, every time that piece of code is run, you will get one random character from the list of acceptable characters.
The map takes a code block and a list as arguments. It runs the code block and returns the result for every item in the list handed to it. The list is 1 .. 64, so the code block will run sixty-four times. Since the code block contains the code that generates a random character, the result of the map function is sixty-four random characters.
The join function takes a delimiter and a list and returns the list as a string delimited by the delimiter (e.g. join ",", "a", "b", "c" returns "a,b,c"). In this case we are using an empty string as the delimiter, so it just produces a string made up of the characters in the list (i.e. the sixty-four random characters).
Now we are ready to look at the substitution. It looks for every instance (because of the /g option) of the string "replace this" and runs the code in the replacement side (because of the /e options) and replaces the string "replace this" with the value of the last statement executed in the replacement side (in this case, the return value of join).
Then why not write a script
#!/bin/bash
for replace in "replace this" "replace that"
do
rand=$(generate random here using /dev/urandom )
sed -i "s/$replace/$rand/" file
done