Here's a very dummy example of what I'm trying to accomplish, input is text:
{placeholder}, John Jones\n{placeholder}, Ben Franklin\n{placeholder}, George Washington
What I want to do is replace every instance of {placeholder} with the output of a function using data from the same line, e.g. the first initial and last name (would need to input first and last name to a function).
def initializer(name):
return f"{name.split(' ')[0][0]}. {name.split(' ')[1]}"
The desired result would be:
J. Jones, John Jones\nB. Franklin, Ben Franklin\nG. Washington, George Washington
A regular expression with a replacement function would work:
import re
s = "{placeholder}, John Jones\n{placeholder}, Ben Franklin\n{placeholder}, George Washington"
def repl_function(m):
return "{}. {}, {} {}".format(m.group(1)[0],m.group(2),m.group(1),m.group(2))
print(re.sub("\{placeholder},\s+(.*?)\s(.*)",repl_function,s))
prints:
J. Jones, John Jones
B. Franklin, Ben Franklin
G. Washington, George Washington
How does it work?
It captures {placeholder} and 2 words (until end of line, not matched by .* because re.DOTALL is not set and creates 2 groups (2 name parts).
On match, it calls the repl_function replacement function with the match object (second parameter of re.sub can be a string, a bytes object or a function which accepts one argument: the match object).
Just return the reformatted match object as string by shortening the first name and repeating the other information (this can be done in a lambda as well, but it's maybe more readable as a real function)
The following will work assuming you are using Python >= 3.6:
# it is the same function you showed in your question
def initializer(name):
return f"{name.split(' ')[0][0]}. {name.split(' ')[1]}"
s = '{placeholder}, John Jones\n{placeholder}, Ben Franklin\n{placeholder}, George Washington'
names = [name.rstrip() for name in s.split('{placeholder}, ') if name != '']
output = '\n'.join(f'{initializer(name)}, {name}' for name in names)
Output
'J. Jones, John Jones\nB. Franklin, Ben Franklin\nG. Washington, George Washington'
Related
I'm having a problem in Excel, where I'm trying to search an entire column for a name (not necessarily 100% identical) that is in another column.
The following table for a better explanation:
---------------------------------------
NAME CITY FATHER NAME
---------------------------------------
Saad Test New York William Jack
Jack Jacking Paris Noah Saad
Adam King Rabat William Sara
Sara Best Madrid Benjamin Adam
Briefly: I want to get the father's name by using only the name column. Is there a way to do that? (The order of the fathers’ names is incorrect, so I want to search using the name, if it is present in the father’s name, then it is the result I want)
Example: Saad test his father's name is Noah Saad (Match by Saad)
PS: I tried using LOOKUP, VLOOKUP and MATCH, but unfortunately the result is always N/A
PS 2: The data I have in Arabic is the reason why the above functions are not working?
I would use index() with match(), assuming your data starts in cell A1, like so:
=index(C1:C4,match(F1,A1:A4,0))
F1 contains the name that you look for.
Note, the classic problem is that there are extra spaces (leading or trailing) that make the names not identical.
You can trap errors as so:
=iferror(index(C1:C4,match(F1,A1:A4,0)),"Check")
You could do:
=INDEX( $C$2:$C$5, MATCH( "*" & MID( A2, 1, FIND( " ", A2 )-1), $C$2:$C$5,0) )
SolarMike - I think you have said the same, so I'm sorry if I am
stepping on your answer.
In my worksheet, B2:F2 and B8:D8 are already filled in.
I would like to find the formulas for B9:D9. For instance, B9 is 2 because we can find Lee in Lee XXXX and Lee is at the second place of B2:F2. C9 is 4 because we can find Jim in Jim XXXX and Jim is at the second place of B2:F2.
To check the relation of Lee and Lee XXXX (Jim and Jim XXXX), we could use SEARCH, left_substring (if such a function exists).
Both single formulas or array formula will be fine. Using LAMBDA function is secondary choice, because it is still in preview.
Could anyone help?
If what is needed is always the first "word":
=MATCH(LEFT(B8,FIND(" ",B8)-1),$B$2:$F$2,0)
If you want to search on any position in the string:
=AGGREGATE(15,7,(COLUMN($B$2:$F$2)-MIN(COLUMN($B$2:$F$2))+1)/(ISNUMBER(SEARCH(" "&$B$2:$F$2&" "," "&B8&" "))),1)
With FILTER instead of AGGREGATE:
=#FILTER((COLUMN($B$2:$F$2)-MIN(COLUMN($B$2:$F$2))+1),ISNUMBER(SEARCH(" "&$B$2:$F$2&" "," "&B8&" ")),"")
I have a question whose variations have already been asked, but I'm not able to find an answer among all previous posts to my particular question. So I hope someone can help me ...
I have a csv file as such (in this example, there are a total of 18 rows, and 4 columns, with the first 2 rows containing headers).
"Employees.csv" 17
ID Name Value Location
25-2002 James 1.2919 Finance
25-2017 Matthew 2.359 Legal
30-3444 Rob 3.1937 Operations
55-8988 Fred 3.1815 Research
26-1000 Lisa 4.3332 Research
56-0909 John 3.3533 Legal
45-8122 Anna 3.8887 Finance
10-1000 Rachel 4.1448 Maintenance
30-9000 Frank 3.7821 Maintenance
25-3000 Angela 5.5854 Service
45-4321 Christopher 9.1598 Legal
44-9821 Maddie 8.5823 Service
20-4000 Ruth 7.47 Operations
50-3233 Vera 5.5092 Operations
65-2045 Sydney 3.4542 Executive
45-8720 Vladimir 0.2159 Finance
I'd like to round the values in the 3rd column to 2 decimals, i.e., round(value, 2). So basically, I want to open the file, read column #3 (minus first 2 rows), round each value, write them back, and save the file. After reading through other similar posts, I've now learned that it's best to always create a temp file to do this work instead of trying to change the same file at once. So I have the following code:
import csv, os
val = []
with open('path/Employees.csv', 'r') as rf, open('path/tmpf.csv, 'w') as tmpf:
reader = csv.reader(rf)
writer = csv.writer(tmpf)
for _ in range(2): #skip first 2 rows
next(reader)
for line in reader:
val.append(float(line[2])) # read 3 column into list 'val'
# [... this is where i got stuck!
# ... how do I round each value of val, and
# ... write everything back to the tmpf file ?]
os.remove('path/Employees.csv')
os.rename('path/tmpf', 'path/Employees.csv')
Thanks!
You could
rounded_val = [ round (v,2) for v in val ]
to generate the list of rounded values.
I have a large spreadsheet that imports basketball statistics from various websites throughout the day and then index-matches them in other tables. My problem is that some websites use a name like "Lou Williams," while others use "Louis Williams." Each time I update one of the tabs with new data, I have to manually correct all the discrepancies between names. Is there a way to write a script that auto corrects the 10-12 names that I am constantly having to fix? I'd love to find some way to do this that is easier than doing a "Find & Replace" 10 different times.
I'd also love if these "spell checks" would happen only on 3 specific tabs, but would also be ok if it happened across the entire worksheet.
I've done some research for a solution but I'm so new to scripting that it's hard to for me to translate other people's code.
Here is a (current) list of the names I frequently have to correct
INCORRECT CORRECT
Louis Williams Lou Williams
Kelly Oubre Kelly Oubre Jr.
Patrick Mills Patty Mills
James Ennis James Ennis III
Alex Abrines Álex Abrines
Guillermo Hernangomez Guillermo Hernangómez
Ishmael Smith Ish Smith
Sergio Rodriguez Sergio Rodríguez
Larry Nance Larry Nance Jr
Luc Mbah a Moute Luc Richard Mbah a Moute
Juan Hernangomez Juancho Hernangómez
Glenn Robinson Glenn Robinson III
There are other ways to do this, but this uses a 'Name List' sheet with correct and incorrect names. Run 'fix' from the custom menu and column A names will change the names to the correct ones. Here is the code and a sample spreadsheet you can copy and run.
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet().addMenu(
'Correct Names', [
{ name: 'Fix', functionName: 'changeNames' },
]);
}
function changeNames() {
var ss=SpreadsheetApp.getActiveSpreadsheet()
var allSheets = ss.getSheets() //get all sheets
var numSheets=allSheets.length
var s=ss.getSheetByName("Name List")//get the list on names to change.
var lr=s.getLastRow()
var rng= s.getRange(2, 1, lr, 2).getValues()
for(var k=0;k<numSheets;k++){//loop through sheets
var s1=ss.getSheets()[k]
var test =s1.getSheetName()
if (s1.getSheetName()== "RG" || s1.getSheetName()=="NF" || s1.getSheetName()=="SWISH"){ //Sheets to process. '||' is OR
var lr1=s1.getLastRow()
var rng1=s1.getRange(2, 1, lr1, 1).getValues()// Assumes names start on eow 2 Column A. Adjust as needed
for(i=0;i<rng1.length;i++){
for(j=0;j<rng.length;j++){
if(rng1[i][0]==rng[j][1]){//if incorrect names match
rng1[i][0]=rng[j][0] //replace incorrect name with correct name
}}}
s1.getRange(2,1, lr1, 1).setValues(rng1)//replace names
}}}
https://docs.google.com/spreadsheets/d/16DPTDTCqzhYTGVmUpb1wlNFI8ZK7xoJNZvobufXapvg/edit?usp=sharing
Changed to only run certain sheets.
I've got autocomplete source with values like 'JOHN SMITH', 'LIN SMITH', JOHN STAINIGER';
I want to enable user if he writes SMITH in the output to see also the suggestions ''JOHN SMITH', 'LIN SMITH' and when he writes SMITH J he should see only JOHN SMITH.
So I've made autocomplete to search both ways - JOHN S and SMITH J will both give me JOHN SMITH
The problem is with bold- I've made this function which makes the req. term item bold no matter where it finds the req. erm in the string.
But if I write SMITH J and that's my req. term then it will bold nothing because it cannot find this req. term in JOHN SMITH. How can i change that?
How can i change that
function monkeyPatchAutocomplete() {
$.ui.autocomplete.prototype._renderItem = function (ul, item) {
var highlighted = item.label.split(this.term).join('<strong>' + this.term + '</strong>');
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + highlighted + "</a>")
.appendTo(ul);
}
}