Is it possible to read the format of a cell from an excell sheet and determinde which words are bold or italic?
I can read and write to cells, and I also know that JExcel can write formatted cells. In formatted cells I mean that the text is italic, or bold.
Is it possible the read a cell data and determine which words are bold?
For instance I will have this in cell:
"A sample text from one excel cell"
I want to know that the string "excel cell" is bold, and the string "sample" is Italic.
Is this possible in JExcel, if not how would I do that in Java? Can somebody suggest an API?
Maybe a better approach would be to pares an xml file.
I don't know about JExcel, but I can tell you this is fairly easy to do in Apache POI. Here is a simple application to show one way it can be done. It isn't incredibly pretty, but it should be enough to get you started:
public static final void main(String... args) throws Exception
{
InputStream is = ExcelFormatTest.class.getResourceAsStream("Test.xlsx");
Workbook wb = new XSSFWorkbook(is);
Sheet sheet = wb.getSheetAt(0);
Cell cell = sheet.getRow(0).getCell(0);
XSSFRichTextString richText = (XSSFRichTextString)cell.getRichStringCellValue();
int formattingRuns = cell.getRichStringCellValue().numFormattingRuns();
for(int i = 0; i < formattingRuns; i++)
{
int startIdx = richText.getIndexOfFormattingRun(i);
int length = richText.getLengthOfFormattingRun(i);
System.out.println("Text: " + richText.getString().substring(startIdx, startIdx + length));
if(i == 0)
{
short fontIndex = cell.getCellStyle().getFontIndex();
Font f = wb.getFontAt(fontIndex);
System.out.println("Bold: " + (f.getBoldweight() == Font.BOLDWEIGHT_BOLD));
System.out.println("Italics: " + f.getItalic() + "\n");
}
else
{
Font f = richText.getFontOfFormattingRun(i);
System.out.println("Bold: " + (f.getBoldweight() == Font.BOLDWEIGHT_BOLD));
System.out.println("Italics: " + f.getItalic() + "\n");
}
}
}
Basically, you get a RichTextString object from a cell (make sure it is a String cell first, though), then iterate over the formatting runs and check the font for each one. It looks like the first run uses the Cell's CellStyle/font, so you have to look it up that way (you get an NPE if you try to get it from the RichTextString).
Once you have the font, you can get all of its attributes. Here is the Javadoc for POI's Font.
If you are using older, non-XLSX files, replace XSSF with HSSF in the class names, and you'll have to change the RichTextString code a bit to lookup the font using the font index. Here are the JavaDocs for XSSFRichTextString and HSSFRichTextString.
Running this with the following in Sheet 1, A1: "A sample text from one excel cell" gives the following results:
Text: A
Bold: false
Italics: false
Text: sample
Bold: true
Italics: false
Text: text
Bold: false
Italics: false
Text: from
Bold: false
Italics: true
Text: one
Bold: false
Italics: false
Text: excel cell
Bold: true
Italics: true
Here's how I'd do it in VBA. Maybe you can translate:
Sub ListBoldStrings()
Dim cell As Excel.Range
Dim i As Long
Dim BoldChars As String
Dim BoldStrings() As String
'replace "|" with a char that will not appear in evaluated strings
Const SEPARATOR_CHAR As String = "|"
Set cell = ActiveCell
With cell
For i = 1 To .Characters.Count
If .Characters(i, 1).Font.Bold Then
BoldChars = BoldChars + .Characters(i, 1).Text
Else
BoldChars = BoldChars + SEPARATOR_CHAR
End If
If Right$(BoldChars, 2) = WorksheetFunction.Rept(SEPARATOR_CHAR, 2) Then
BoldChars = Left$(BoldChars, Len(BoldChars) - 1)
End If
Next i
End With
BoldStrings = Split(BoldChars, SEPARATOR_CHAR)
For i = LBound(BoldStrings) To UBound(BoldStrings)
Debug.Print BoldStrings(i)
Next i
End Sub
Related
Java 8 and Apache POI 4.1.x here. I need to:
Read in a template Excel file, that just has a single row of pre-styled header columns
Write a List<Fizz> (POJO list) to a new Excel file that uses that template
I do this because the template Excel has lots of complicated stylings, and so just using an existing one as a template input was much easier than me trying to manually generate the stylings myself via POI and CellUtil.
I have this working perfectly fine like so:
List<Fizz> fizzes = getSomehow();
InputStream inp = this.getClass().getClassLoader().getResource("my-template.xlsx").openStream();
Workbook workbook = WorkbookFactory.create(inp);
Sheet sheet = workbook.getSheetAt(0);
// the header is at row = 0 (0-based rows)
// so start writing the list on the row=1 (1st data/non-header row)
int rowNum = 1;
for (Fizz fizz : fizzes) {
Row nextRow = sheet.createRow(rowNum);
Cell itemNumber = nextRow.createCell(0);
itemNumber.setCellValue(fizz.getItemNumber());
Cell description = nextRow.createCell(1);
description.setCellValue(fizz.getDescription());
rowNum++;
}
// resize the columns appropriately
for (int c = 0; c < 2; c++) {
sheet.autoSizeColumn(c);
}
// export to file system
FileOutputStream fos = new FileOutputStream("some-output.xlsx");
workbook.write(fos);
fos.close();
inp.close();
workbook.close();
Everything works great, with one exception: often the Fizz#description is pretty lengthy, and is sometimes hundreds of characters long. Because there is no use of text wrapping in my code, and because I use autoSizeColumn for all columns, POI is setting the Description column width to the length of the longest-description.
Instead, I now want to stop using autoSizeColumn (I think!) and instead:
Force the output file's (in our case, "some-output.xlsx") Description column width to be the same as the input template file's Description's column. So if the Description column on my-template.xlsx is, say, 54, then I want some-output.xlsx's Description column to also be 54.
If the current row's Fizz description is too long for that width, I want to apply text wrapping so that the column stays fixed (again, in this case, 54) but that the description fits inside of it.
I would like to do this for every column, and ideally, I would like the code to detect what the width is for each column on the template. I say that because I would like to be able to open the template in Excel, change its width manually, save it, then re-run my code and have it pick up on that width change.
Any ideas on what I can do to accomplish this?
First approach
Set wrap text cell style for whole description column (column B) in your template using Excel's GUI. Then do using following getPreferredCellStyle method to get that column cell style and set it as the preferred cell style for each cell in description column (column B).
CellStyle getPreferredCellStyle(Cell cell) {
// a method to get the preferred cell style for a cell
// this is either the already applied cell style
// or if that not present, then the row style (default cell style for this row)
// or if that not present, then the column style (default cell style for this column)
CellStyle cellStyle = cell.getCellStyle();
// if no explicit cell style applied then cellStyle.getIndex() is 0 for XSSF
// or 15 (0xF = the index to the default ExtendedFormatRecord (0xF)) for HSSF
if ((cell instanceof XSSFCell && cellStyle.getIndex() == 0) || (cell instanceof HSSFCell && cellStyle.getIndex() == 15)) cellStyle = cell.getRow().getRowStyle();
if (cellStyle == null) cellStyle = cell.getSheet().getColumnStyle(cell.getColumnIndex());
if (cellStyle == null) cellStyle = cell.getCellStyle();
return cellStyle;
}
Then
...
Cell description = nextRow.createCell(1);
description.setCellValue(fizz.getDescription());
description.setCellStyle(getPreferredCellStyle(description));
...
Second approach
Do using CellUtil to set wrap text cell style for each cell in description column.
...
Cell description = nextRow.createCell(1);
description.setCellValue(fizz.getDescription());
CellUtil.setCellStyleProperty(description, CellUtil.WRAP_TEXT, true);
...
For both approaches
Do not set autoSizeColumn for the description column (column B). In your example, only autosize column 0 (A) but not column 1 (B):
...
sheet.autoSizeColumn(0);
...
So the column width of column B remains unchanged as width as it is in the template.
I have one excel file in which a row contains few cell as string and other as numeric, hyperlink.
I want to read the data from excel for that I wrote below code
HSSFCell cell =row.getCell(j+1);
cell.setCellType(CellType.STRING);
String cellValue = cell.getStringCellValue();
above code reads numeric cells and string cells but when it comes to the cells which contain a hyperlink, in that case, it is reading those cells as null.I can put my hyperlink between double quotes("abc#cd.com") in the sheet but I want to handle this on the code level. Is there any way to handle this scenario?
You should use cell.getHyperlink() to get a hyperlink from the cell.
if(cell.getCellTypeEnum() == CellType.STRING){
Hyperlink hyperlink = cell.getHyperlink();
String value = cell.getRichStringCellValue().getString();
if(hyperlink == null) {
return value;
} else {
return value + " " + hyperlink.getAddress();
}
}
I am using Apache-POI 3.14. I have a need to lock-down a cell to a "Text" format. The data in my cell might be all digits, but it is still considered a string. When I write the cell, I do it like this:
cell.setCellValue("001");
cell.setCellType(Cell.CELL_TYPE_STRING);
When I open the output workbook in Excel, the cell contains the correct value ("001") and it displays with a small green triangle in the corner. Hovering over the exclamation point displays the hover text The number in this cell is formatted as text or preceded by an apostrophe. When I look at the cell formatting (Right-click -> Format cells), the "Category" is displayed as "General". I expected this to be "Text".
The problem arises when a user modifies the value in the cell by entering only digits. Because the "Category" is "General", the value is entered and displayed as a number, removing leading zeroes and right-justified.
How can I achieve the same result as Excel's "Format cells" dialog?
You can try to set the cell-format to text via
DataFormat fmt = wb.createDataFormat();
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setDataFormat(
fmt.getFormat("#"));
cell.setCellStyle(cellStyle);
Note: CellStyles shoudl be re-used for all applicable cells, do not create new ones for every cell.
You could also try to use the "Ignore errors" feature in the .xlsx format, however support for it is not fully done yet, see Issue 46136 and Issue 58641 for some ongoing discussion.
See also this MSDN page for some additional information
For HSSF,
DataFormat fmt = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(fmt.getFormat("#"));
sheet.setDefaultColumnStyle(0, textStyle);
It just sets the whole column style as Text and set category as Text .
However, if you are using XSSF format, it doesn't work(I am using Apache Poi 3.15 and didn't work for me).
In this case you have set style to each cell you want to treat as text in addition to above code using:
cell.setCellStyle(textStyle);
Regarding error, you could use
sheet.addIgnoredErrors(new CellRangeAddress(0,9999,0,9999),IgnoredErrorType.NUMBER_STORED_AS_TEXT );
It ignores the NUMBER_STORED_AS_TEXT error for row 0 till 9999 and column 0 till 9999 and you wont see it.
Look like OP was asking for Apache solution. After some searching I found this answer:
HSSFCellStyle style = book.createCellStyle();
style.setDataFormat(BuiltInFormats.getBuiltInFormat("text"));
In this case, I'm using Apache-POI 3.15, and I had the same problem, so I validated the data in my style, I need numbers >0 and strings:
try {
if (Integer.parseInt(field + "") >= 0) {
int valor = Integer.parseInt(field + "");
cell.setCellValue(valor); //Int
}
} catch (NumberFormatException nfe) {
// no int
try {
if (Double.parseDouble(field + "") >= 0) {
double valor = Double.parseDouble(field + ""); //double
cell.setCellValue(valor);
}
} catch (NumberFormatException nfe2) {
cell.setCellValue(field + ""); //String
}
}
For Apache POI 4.0.1 :
XSSFSheet sheet = workbook.createSheet("MySheetName");
sheet.addIgnoredErrors(new CellRangeAddress(0, 9999, 0, 9999), IgnoredErrorType.NUMBER_STORED_AS_TEXT);
Be careful to cast your sheet to org.apache.poi.xssf.usermodel.XSSFSheet and not to org.apache.poi.ss.usermodel.Sheet, otherwise the method addIgnoredErrors wil be unknown.
I am using Apache POI library to read/write to xlsx. In my original xlsx, I have a namedrange "XYZ".
I want to update the values of cells within this name range. How can I do that?
I did this:
XSSFName name = workbook.getName("XYZ");
String formula = name.getRefersToFormula();
System.out.println("Formula = " + formula);
Now, I dont know how to get a handle to individual cell in this named range.
Can anyone please point me to the correct API that I can use?
Rgds
Sapan
There is an example from the Busy Developers' Guide for retrieving the cells in the range. Then you can use Cell.setCellValue() to update.
// setup code
String cname = "TestName";
Workbook wb = getMyWorkbook(); // retrieve workbook
// retrieve the named range
int namedCellIdx = wb.getNameIndex(cname);
Name aNamedCell = wb.getNameAt(namedCellIdx);
// retrieve the cell at the named range and test its contents
AreaReference aref = new AreaReference(aNamedCell.getRefersToFormula());
CellReference[] crefs = aref.getAllReferencedCells();
for (int i=0; i<crefs.length; i++) {
Sheet s = wb.getSheet(crefs[i].getSheetName());
Row r = s.getRow(crefs[i].getRow());
Cell c = r.getCell(crefs[i].getCol());
// extract the cell contents based on cell type etc.
}
I am reading an Excel sheet using POI's XSSF . The Excel sheet has thousands of rows of user information like user name, address, age, department etc.
I can read and write the Excel sheet successfully but i want to locate empty/null cell's address and want to print it as result in another sheet
example result what i want is:
Empty cell : C5
Empty cell : E7
Empty cell : H8
Thanks and appreciate for discussions and replies.
You need to check for both Null and Blank cells. Null cells are ones that have never been used, Blank ones are ones that have been used or styled in some way that Excel has decided to keep them around in the file
The easiest way to control this fetching is with a MissingCellPolicy. Your code can then be something like:
Row r = getRow(); // Logic here to get the row of interest
// Iterate over all cells in the row, up to at least the 10th column
int lastColumn = Math.max(r.getLastCellNum(), 10);
for (int cn = 0; cn < lastColumn; cn++) {
Cell c = r.getCell(cn, Row.RETURN_BLANK_AS_NULL);
if (c == null) {
// The spreadsheet is empty in this cell
} else {
// Do something useful with the cell's contents
// eg...
System.out.println("There is data in cell " + (new CellReference(c)).formatAsString());
}
}
You can find more on this in the POI docs on iterating over rows and cells
As far as I unterstood your question right, this should do the trick:
XSSFCell cell = (XSSFCell) row.getCell( index );
if( cell == null )
{
cell = (XSSFCell) row.createCell( index );
}
if( cell.getStringCellValue().trim().isEmpty() )
{
String cellRef = CellReference.convertNumToColString( cell.getColumnIndex() );
System.err.println( "Empty cell found: " + cellRef
+ Integer.toString( row.getRowNum() ) );
}