I have a Python class that does some currency conversion and string formatting of numbers. It takes polymorphic input, but only spits out a stringified number. I can push those stringified numbers up to a LibreOffice Calc in Python easy enough:
stringifiednumber = str("1.01")
cell_a1 = sheet1.getCellRange("A1")
cell_a1.String = stringifiednumber
This actually works nicely since the builtin currency formats in Calc work just fine with stringified numbers.
What doesn't work is formulas, or sort of doesn't work. Calling SUM(A1:A2) will not see the stringified A1. There is a workaround (forgive me it is late and I forget it exactly but it is similar to:) =SUMRECORD(VALUE(A1:A2)).
As I understand it, each cell has a memory location for a number, a string, and a formula. The formula only acts on the VALUE memory location.
Through the spreadsheet UI, I can convert one cell type to another during a copy. To do that I just put the following formula in A2, and it converts STRING(A1) to VALUE( A2):
# formula placed in A2
=VALUE(A1)
but that only works by copying one cell to another. Obviously there is an internal recasting function within the spreadsheet that is doing the conversion during the copy.
What I want to do, is write a stringified number to the spreadsheet (as above) and then call the spreadsheets native recasting function in place from Python, so that VALUE(A1) is recast from STRING(A1).
If I knew what the recasting function was I could just call it after every string write. This would make macros in the UI work like the user expects them to work.
If your answer is: "do type conversion Python-side", I've already considered that, and it is not the solution I'm looking for.
Based on your Title, multiply by 1:
Related
I want to create a listobject object with xlwings, the basic code I succeeded in:
sht.api.ListObjects.Add(SourceType=1,Source="A1:N18").Name = "list1"
But there is a big problem, in the parameter Source, it seems that you can only enter cell values with letters like A1:N18. My cell size is not fixed, I need to use the Range ((1,1), (18,15)) such as the use of numbers to indicate the range, how do I do? What other types of ranges does this parameter Source accept?
Let's say I have a pretty large text document.
I need to imitate copy and paste operation of a text editor.
More concretely,
I want to write two functions copy(i,j) and paste(i), where i and j represent indices of characters in the text document.
Now, I understand that normal string slicing creates a new string object every time and doing something like
copy_text = str[i:j]
self.str = str[:i] + copy_text + str[j:]
will end up creating a lot of overhead of new string objects, given how many times we do a copy-paste function in a text editor.
How do I do it? Is it even possible?
I've looked into memoryview, where in they make use of a buffer, which may end up taking less time to execute given they create a zero-copy view of the original object. However, I want to do it algorithmacally and not play around with how strings are stored.
I've thinking on the lines of an array to store the string and use a B+ tree to store pointers to that string. I haven't been able to really materialize anything.
Look forward to your comments. Thanks.
I have a config file, in which items can be single element or list.
pct_accepted=0.75
pct_rejected=0.35, 0.5
Upon reading back, they will all be in string,
config['pct_accepted']='0.75'
config['pct_rejected']=['0.35', '0.5']
Is there a clean method of converted them to float other than having to check whether they are scalar or list
My attempt for now is :
for k in ['pct_accepted','pct_rejected']:
if isinstance(config[k], list) :
config[k]=[float(item) for item in config[k]]
if isinstance(config[k], string) :
config[k]=float(config[k])
Doesn't look so neat.
Since you included the numpy tag:
In [161]: np.array('12.23',float).tolist()
Out[161]: 12.23
In [162]: np.array(['12.23','12.23'],float).tolist()
Out[162]: [12.23, 12.23]
short, sweet and overkill!
There's no clean way, simply because the conversion is not valid on a list: something has to look at the data type. You can hide that in a function, but it's still there.
You can shorten the code a bit by using the available broadcast routines. Something such as map(float, config[k]) will perhaps make it look a little better to you.
You can also store the type in a variable, and test the variable twice, rather than using two isinstance calls. This saves a few characters, and doesn't scale well, but it works nicely for simple applications.
There are numerous questions about how to stop Excel from interpreting text as a number, or how to output number formats with openpyxl, but I haven't seen any solutions to this problem:
I have an Excel spreadsheet given to me by someone else, so I did not create it. When I open the file with Excel, I have certain values like "5E12" (clone numbers, if anyone cares) that appear to display correctly, but there's a little green arrow next to each one warning me that "This appears to be a number stored as text". Excel then asks me if I would like to convert it to a number, and if I saw yes, I get 5000000000000, which then converts automatically to scientific notation and displays 5E12 again, only this time a text output would show the full number with zeroes. Note that before the conversion, this really is text, even to Excel, and I'm only being warned/offered to convert it.
So, when reading this file in with openpyxl (from openpyxl.reader.excel import load_workbook), the 5E12 is getting converted automatically to 5000000000000. I assume that openpyxl is making the same assumption that Excel made, only the conversion happens without a prompt or input on my part.
How can I prevent this from happening? I do not want text that look like "numbers stored as text" to convert to numbers. They are text unless I say so.
So far, the only solution I have found is to add single quotes to the front of each cell, but this is not an ideal solution, as it's manual labor rather than a programmatic solution. Also, the solution needs to be general, since I don't always know where this problem might occur (I'm reading millions of lines per day, so I don't want to have to do anything by hand).
I think this is a problem with openpyxl. There is a google group discussion from the beginning of 2011 that mentions this problem, but assumes it's too rare to matter. https://groups.google.com/forum/?fromgroups=#!topic/openpyxl-users/HZfpShMp8Tk
So, any suggestions?
If you want to use openpyxl again (for whatever reason), the following changes to the worksheet reader routine do the trick of keeping the strings as strings:
diff --git a/openpyxl/reader/worksheet.py b/openpyxl/reader/worksheet.py
--- a/openpyxl/reader/worksheet.py
+++ b/openpyxl/reader/worksheet.py
## -134,8 +134,10 ##
data_type = element.get('t', 'n')
if data_type == Cell.TYPE_STRING:
value = string_table.get(int(value))
-
- ws.cell(coordinate).value = value
+ ws.cell(coordinate).set_value_explicit(value=value,
+ data_type=Cell.TYPE_STRING)
+ else:
+ ws.cell(coordinate).value = value
# to avoid memory exhaustion, clear the item after use
element.clear()
The Cell.value is a property and on assignment call Cell._set_value, which then does a Cell.bind_value which according to the method's doc: "Given a value, infer type and display options". As the types of the values are in the XML file those should be taken (here I only do that for strings) instead of doing something 'smart'.
As you can see from the code, the test whether it is a string was already there.
I am using python to read a currency value from excel. The returned from the range.Value method is a tuple that I don't know how to parse.
For example, the cell appears as $548,982, but in python the value is returned as (1, 1194857614).
How can I get the numerical amount from excel or how can I convert this tuple value into the numerical value?
Thanks!
Try this:
import struct
try: import decimal
except ImportError:
divisor= 10000.0
else:
divisor= decimal.Decimal(10000)
def xl_money(i1, i2):
byte8= struct.unpack(">q", struct.pack(">ii", i1, i2))[0]
return byte8 / divisor
>>> xl_money(1, 1194857614)
Decimal("548982.491")
Money in Microsoft COM is an 8-byte integer; it's fixed point, with 4 decimal places (i.e. 1 is represented by 10000). What my function does, is take the tuple of 4-byte integers, make an 8-byte integer using struct to avoid any issues of sign, and then dividing by the constant 10000. The function uses decimal.Decimal if available, otherwise it uses float.
UPDATE (based on comment): So far, it's only COM Currency values being returned as a two-integer tuple, so you might want to check for that, but there are no guarantees that this will always be successful. However, depending on the library you use and its version, it's quite possible that later on, after some upgrade, you will be receiving decimal.Decimals and not two-integer tuples anymore.
I tried this with Excel 2007 and VBA. It is giving correct value.
1) Try pasting this value in a new excel workbook
2) Press Alt + F11. Gets you to VBA Editor.
3) Press Ctrl + G. Gets you to immediate window.
4) In the immediate window, type ?cells("a1").Value
here "a1" is the cell where you have pasted the value.
I am doubting that the cell has some value or character due to which it is interpreted this way.
Post your observations here.