Python Find all letter chars in string and surround with text - string

So lets say I have a string that says "m * x + b", I want to find any letter chars, other than x, and surround them with text.
In this example, output should be "var['m'] * x + var['b']"

A tiny regular expression solves your problem:
import re
s = "m * x + b"
print re.sub("([a-wyzA-Z])", r"var['\1']", s)
Output:
var['m'] * x + var['b']
Explanation:
[a-wyzA-Z] matches all characters within the brackets: a-w, y, z and A-Z (so basically every letter but x)
(...) makes the found match accessible later via \1
r"var['\1']" is the replacement referring to the match\1`

Related

Is there a way to replace characters in a string from index 0 to index -4 (i.e. all but last 4 characters) with a '#'

For example, If my string was 'HelloWorld'
I want the output to be ######orld
My Code:
myString = 'ThisIsAString'
hashedString = string.replace(string[:-4], '#')
print(hashedString)
Output >> #ring
I expected the output to have just one # symbol since it is replacing argument 1 with argument 2.
Can anyone help me with this?
You could multiply # by the word length - 4 and then use the string slicing.
myString = 'HelloWorld'
print('#' * (len(myString) - 4) + myString[-4:])
myString = 'ThisIsAString'
print('#' * (len(myString) - 4) + myString[-4:])
string.replace(old, new) replaces all instances of old with new. So the code you provided is actually replacing the entire beginning of the string with a single pound sign.
You will also notice that input like abcdabcd will give the output ##, since you are replacing all 'abcd' substrings.
Using replace, you could do
hashes = '#' * len(string[:-4])
hashedString = string.replace(string[:-4], hashes, 1)
Note the string multiplication to get the right number of pound symbols, and the 1 passed to replace, which tells it only to replace the first case it finds.
A better method would be to not use replace at all:
hashes = '#' * (len(string) - 4)
leftover = string[-4:]
hashedString = hashes + leftover
This time we do the same work with getting the pound sign string, but instead of replacing we just take the last 4 characters and add them after the pound signs.

Can we use for loop and if else in a single lambda function at once? so it can check values while working inside loop

Have the function LetterChanges(str). Take the str parameter being passed and modify it using the following algorithm. Replace every letter in the string with the letter following it in the alphabet (ie. c becomes d, z becomes a).
Then capitalize every vowel in this new string (a, e, i, o, u) and finallyreturn this modified string.
I want this problem done in 2 lines
a= lambda stri:([(chr(ord(i) + 1)) for i in stri]) #if i not in ("a","e","i","o","u")
print(a("bcdefgh"))
I know that if part is wrong, to understand clearly, I included it in comment.
Expected output is "cdEfgI".
Your expected output does not match your input, you are missing an h before the final I.
Assuming this is just a typo, your problem can be solved with:
>>> a = lambda stri: ''.join('A' if i == 'z' else chr(ord(i) + (-31 if i in "dhnt" else 1)) for i in stri)
>>> print(a("bcdefgh"))
cdEfghI
Explanation:
first check if i is a z then return an A
otherwise check if i is any character preceding a vowel in the alphabet then subtract 31 from it to get the capitalized vowel
if that is not the case, increase the character by one
Here's the normal code (that you should have already made):
def change_letters(string):
result = ''
for letter in string:
# This makes sure that 'z' goes to 'a'
next_letter = chr((ord(letter) - 98)%26 + 97)
if next_letter in 'aeiou':
result += letter.upper()
else:
result += letter
return string
If we follow the steps in my other answer here, we end up with the following:
change_letters = lambda string: ''.join(chr((ord(letter) - 98)%26 + 97).upper() if chr((ord(letter) - 98)%26 + 97) in 'aeiou' else chr((ord(letter) - 98)%26 + 97) for letter in string)
But please note, this is a HORRIBLE thing to do, especially for your future self and others you may one day be working with. I would not want to see this again :)

count the number of words in a string separated by spaces and/or punctuation marks

Can someone help please .
I want to create a program that can count the number of words in a string separated by spaces and/or punctuation marks. You should only count words where the vowels and consonants are alternating. A word can not have two consecutive vowels or consonants. Single letter words are not counted. Ignore anything in the file that is not a vowel or a constant. Replace anything that is not in the alphabet with a single space. Case sensitivity of each letter does not matter.
Alphabet to use
Vowels -- A E I O U Y
Consonants -- B C D F G H J K L M N P Q R S T V W X Z
Input:
A string eg "Hello there great new world"
Output:
Number of desired words found in the input string above. eg 1
Sample:
"Welcome to Radix!!!" == 2 (to Radix)
"Everybody, thanks you for trying this out." == 2 (everybody for)
"Hello there great new world" == 1 (new)
"Mary,had,a,little,lamb" == 2 (Mary had)
This is a homework, isn't it?
Try this regular expression:
\b[aeiouy]?([bcdfghjklmnpqrstvwxz][aeiouy])*[bcdfghjklmnpqrstvwxz]?\b
It will find all words with alternating vowels/consonants. Beware, it will pass single-letter words as well, filter them out subsequently. And run it with ignore-case flag.
import string,re
VOWELS=[x.lower() for x in "A E I O U Y".split(" ")]
CONSONANTS = [x.lower() for x in "B C D F G H J K L M N P Q R S T V W X Z".split(" ") ]
FILE_PATH = 'sentences.txt'
PUNCT = '[ %s]'% string.punctuation #[ !"#$%&'()*+,-./:;<=>?#[\]^_`{|}~]
def isAlt(word):
#True if word is valid
word=word.lower() #Non-case-sensitive
for x in range(len(word)-1):
if not (word[x] in VOWELS and word[x+1] in CONSONANTS)and not(word[x+1] in VOWELS and word[x] in CONSONANTS):
#Sorry about that condition, I can probably return that whole line
return False
return True
for line in open(FILE_PATH,'r'):
out=re.split(PUNCT,line.strip())
out=[x for x in out if x and len(x)>1 and isAlt(x)]
print(len(out))
This scans the file and for each line finds the valid words and prints out the number of words that match your conditions. You can change len(out) to out for the list instead of the number.

Insert quoted and unquoted parts of string in table

I've been working on this part of a saycommand system which is supposed to separate parts of a string and put them in a table which is sent to a function, which is queried at the beginning of the string. This would look like, for example, !save 1 or !teleport 0 1, or !tell 5 "a private message".
I would like this string to turn into a table:
[[1 2 word 2 9 'more words' 1 "and more" "1 2 34"]]
(Every non-quoted part of the string gets its own key, and the quoted parts get grouped into a key)
1 = 1
2 = 2
3 = word
4 = 2
5 = 9
6 = more words
7 = 1
8 = and more
9 = 1 2 34
I've tried doing this with Lua pattern, but I'm stuck trying to find out how to capture both quoted and unquoted pieces of the string. I've tried a lot of things, but nothing helped.
My current pattern attempts look like this:
a, d = '1 2 word 2 9 "more words" 1 "and more" "1 2 34"" ', {}
-- previous attempts
--[[
This one captures quotes
a:gsub('(["\'])(.-)%1', function(a, b) table.insert(d, b) end)
This one captures some values and butchered quotes,
which might have to do with spaces in the string
a:gsub('(["%s])(.-)%1', function(a, b) table.insert(d, b) end)
This one captures every value, but doesn't take care of quotes
a:gsub('(%w+)', function(a) table.insert(d, a) end)
This one tries making %s inside of quotes into underscores to
ignore them there, but it doesn't work
a = a:gsub('([%w"\']+)', '%1_')
a:gsub('(["\'_])(.-)%1', function(a, b) table.insert(d, b) end)
a:gsub('([%w_]+)', function(a) table.insert(d, a) end)
This one was a wild attempt at cracking it, but no success
a:gsub('["\']([^"\']-)["\'%s]', function(a) table.insert(d, a) end)
--]]
-- This one adds spaces, which would later be trimmed off, to test
-- whether it helped with the butchered strings, but it doesn't
a = a:gsub('(%w)(%s)(%w)', '%1%2%2%3')
a:gsub('(["\'%s])(.-)%1', function(a, b) table.insert(d, b) end)
for k, v in pairs(d) do
print(k..' = '..v)
end
This would not be needed for simple commands, but a more complex one like !tell 1 2 3 4 5 "a private message sent to five people" does need it, first to check if it's sent to multiple people and next to find out what the message is.
Further down the line I want to add commands like !give 1 2 3 "component:material_iron:weapontype" "food:calories", which is supposed to add two items to three different people, would benefit greatly from such a system.
If this is impossible in Lua pattern, I'll try doing it with for loops and such, but I really feel like I'm missing something obvious. Am I overthinking this?
You cannot process quoted strings with Lua patterns. You need to parse the string explicitly, as in the code below.
function split(s)
local t={}
local n=0
local b,e=0,0
while true do
b,e=s:find("%s*",e+1)
b=e+1
if b>#s then break end
n=n+1
if s:sub(b,b)=="'" then
b,e=s:find(".-'",b+1)
t[n]=s:sub(b,e-1)
elseif s:sub(b,b)=='"' then
b,e=s:find('.-"',b+1)
t[n]=s:sub(b,e-1)
else
b,e=s:find("%S+",b)
t[n]=s:sub(b,e)
end
end
return t
end
s=[[1 2 word 2 9 'more words' 1 "and more" "1 2 34"]]
print(s)
t=split(s)
for k,v in ipairs(t) do
print(k,v)
end
Lua string patterns and regex for that matter generally aren't well suited when you need to do parsing that requires varying nesting levels or token count balancing like parenthesis ( ). But there is another tool available to Lua that's powerful enough to deal with that requirement: LPeg.
The LPeg syntax is a bit archaic and takes some getting use to so I'll use the lpeg re module instead to make it easier to digest. Keep in mind that anything you can do in one form of the syntax you can also express in the other form as well.
I'll start by defining the grammar for parsing your format description:
local re = require 're'
local cmdgrammar =
[[
saycmd <- '!' cmd extra
cmd <- %a%w+
extra <- (singlequote / doublequote / unquote / .)*
unquote <- %w+
singlequote <- "'" (unquote / %s)* "'"
doublequote <- '"' (unquote / %s)* '"'
]]
Next, compile the grammar and use it to match some of your test examples:
local cmd_parser = re.compile(cmdgrammar)
local saytest =
{
[[!save 1 2 word 2 9 'more words' 1 "and more" "1 2 34"]],
[[!tell 5 "a private message"]],
[[!teleport 0 1]],
[[!say 'another private message' 42 "foo bar" baz]],
}
There are currently no captures in the grammar so re.match returns the last character position in the string it was able to match up to + 1. That means a successful parse will return the full character count of the string + 1 and therefore is a valid instance of your grammar.
for _, test in ipairs(saytest) do
assert(cmd_parser:match(test) == #test + 1)
end
Now comes the interesting part. Once you have the grammar working as desired you can now add captures that automatically extracts the results you want into a lua table with relatively little effort. Here's the final grammar spec + table captures:
local cmdgrammar =
[[
saycmd <- '!' {| {:cmd: cmd :} {:extra: extra :} |}
cmd <- %a%w+
extra <- {| (singlequote / doublequote / { unquote } / .)* |}
unquote <- %w+
singlequote <- "'" { (unquote / %s)* } "'"
doublequote <- '"' { (unquote / %s)* } '"'
]]
Running the tests again and dumping the re.match results:
for i, test in ipairs(saytest) do
print(i .. ':')
dump(cmd_parser:match(test))
end
You should get output similar to:
lua say.lua
1:
{
extra = {
"1",
"2",
"word",
"2",
"9",
"more words",
"1",
"and more",
"1 2 34"
},
cmd = "save"
}
2:
{
extra = {
"5",
"a private message"
},
cmd = "tell"
}
3:
{
extra = {
"0",
"1"
},
cmd = "teleport"
}
4:
{
extra = {
"another private message",
"42",
"foo bar",
"baz"
},
cmd = "say"
}

string matching in matlab

I have two short (S with the size of 1x10) and very long (L with the size of 1x1000) strings and I am going to find the locations in L which are matched with S.
In this specific matching, I am just interested to match some specific strings in S (the black strings). Is there any function or method in matlab that can match some specific strings (for example string numbers of 1, 5, 9 in S)?
If I understand your question correctly, you want to find substrings in L that contain the same letters (characters) as S in certain positions (let's say given by array idx). Regular expressions are ideal here, so I suggest using regexp.
In regular expressions, a dot (.) matches any character, and curly braces ({}) optionally specify the number of desired occurrences. For example, to match a string of length 6, where the second character is 'a' and the fifth is 'b', our regular expression could be any of the following syntaxes:
.a..b.
.a.{2}b.
.{1}a.{2}b.{1}
any of these is correct. So let's construct a regular expression pattern first:
in = num2cell(diff([0; idx(:); numel(S) + 1]) - 1); %// Intervals
ch = num2cell(S(idx(:))); %// Matched characters
C = [in(:)'; ch(:)', {''}];
pat = sprintf('.{%d}%c', C{:}); %// Pattern for regexp
Now all is left is to feed regexp with L and the desired pattern:
loc = regexp(L, pat)
and voila!
Example
Let's assume that:
S = 'wbzder'
L = 'gabcdexybhdef'
idx = [2 4 5]
First we build a pattern:
in = num2cell(diff([0; idx(:); numel(S) + 1]) - 1);
ch = num2cell(S(idx(:)));
C = [in(:)'; ch(:)', {''}];
pat = sprintf('.{%d}%c', C{:});
The pattern we get is:
pat =
.{1}b.{1}d.{0}e.{1}
Obviously we can add code that beautifies this pattern into .b.de., but this is really an unnecessary optimization (regexp can handle the former just as well).
After we do:
loc = regexp(L, pat)
we get the following result:
loc =
2 8
Seems correct.

Resources