1

我有一个程序,它使用 JExcel 库来读取 excel 表并对其进行一些处理。

我注意到的一次令人不安的事情(在我们的一位用户通知之后)是 JExcel 似乎强制将格式化为货币单元格的单元格转换为使用 $ 符号。我已经进行了很多挖掘,但我看不到下一步该去哪里。跳到底部看看问题的症结所在。

本质上,我们有这个方法:

import java.io.File;
import java.io.IOException;
import java.util.Locale;

import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.read.biff.BiffException;

public class Launcher {

    /**
     * @param args
     */
    public static void main(String[] args) {
        nothingSpecifc("D:\\Documents and Settings\\castone\\My Documents\\JExcelCurrencyExample.xls");
    }
    public static void nothingSpecifc(String excelFilePath){
       try { 
           File myFile = new File(excelFilePath);
           Locale myLocal = Locale.UK;
           WorkbookSettings wbkSettings = new WorkbookSettings();
           wbkSettings.setLocale(myLocal);
           wbkSettings.setEncoding("UTF-8");
           wbkSettings.setExcelDisplayLanguage("UK");
           Workbook workbook = Workbook.getWorkbook(myFile,wbkSettings);
           Sheet mySheet = workbook.getSheet(0);
           Cell[] myRow = mySheet.getRow(0);
           String myCellA1 = myRow[0].getContents();
           System.out.println(myCellA1);
        } catch (BiffException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

我的示例 .xls 文件在 A1 中有这个值:

excel文件的屏幕截图,格式化窗口打开

但是运行后,我得到了这个值!

Eclipse 的屏幕截图,输出格式不佳

现在我无法理解为什么会发生这种情况。令人不安的是,我担心我实施的任何修复都会强制将其他货币符号转换为 £ 符号。

查看 Workbook.java,我正在调用此方法:

 /**
   * A factory method which takes in an excel file and reads in the contents.
   *
   * @exception IOException
   * @exception BiffException
   * @param file the excel 97 spreadsheet to parse
   * @param ws the settings for the workbook
   * @return a workbook instance
   */
  public static Workbook getWorkbook(java.io.File file, WorkbookSettings ws)
    throws IOException, BiffException
  {
    FileInputStream fis = new FileInputStream(file);

    // Always close down the input stream, regardless of whether or not the
    // file can be parsed.  Thanks to Steve Hahn for this
    File dataFile = null;

    try
    {
      dataFile = new File(fis, ws);
    }
    catch (IOException e)
    {
      fis.close();
      throw e;
    }
    catch (BiffException e)
    {
      fis.close();
      throw e;
    }

    fis.close();

    Workbook workbook = new WorkbookParser(dataFile, ws);
    workbook.parse();

    return workbook;
  }

所以本质上,这个类只是文件 I/O 处理和 excel 之间的一个聪明的包装器/接口。我正在研究 WorkbookSettings 和 WorkbookParser 的默认构造函数。

一、WorkbookSettings:

  /**
   * Default constructor
   */
  public WorkbookSettings()
  {
    initialFileSize = DEFAULT_INITIAL_FILE_SIZE;
    arrayGrowSize = DEFAULT_ARRAY_GROW_SIZE;
    localeFunctionNames = new HashMap();
    excelDisplayLanguage = CountryCode.USA.getCode();
    excelRegionalSettings = CountryCode.UK.getCode();
    refreshAll = false;
    template = false;
    excel9file = false;
    windowProtected = false;
    hideobj = HIDEOBJ_SHOW_ALL;

    // Initialize other properties from the system properties
    try
    {
      boolean suppressWarnings = Boolean.getBoolean("jxl.nowarnings");
      setSuppressWarnings(suppressWarnings);
      drawingsDisabled        = Boolean.getBoolean("jxl.nodrawings");
      namesDisabled           = Boolean.getBoolean("jxl.nonames");
      gcDisabled              = Boolean.getBoolean("jxl.nogc");
      rationalizationDisabled = Boolean.getBoolean("jxl.norat");
      mergedCellCheckingDisabled =
        Boolean.getBoolean("jxl.nomergedcellchecks");
      formulaReferenceAdjustDisabled =
                                Boolean.getBoolean("jxl.noformulaadjust");
      propertySetsDisabled = Boolean.getBoolean("jxl.nopropertysets");
      ignoreBlankCells = Boolean.getBoolean("jxl.ignoreblanks");
      cellValidationDisabled = Boolean.getBoolean("jxl.nocellvalidation");
      autoFilterDisabled = !Boolean.getBoolean("jxl.autofilter"); 
             // autofilter currently disabled by default
      useTemporaryFileDuringWrite = 
        Boolean.getBoolean("jxl.usetemporaryfileduringwrite");
      String tempdir =
        System.getProperty("jxl.temporaryfileduringwritedirectory");

      if (tempdir != null)
      {
        temporaryFileDuringWriteDirectory = new File(tempdir);
      }

      encoding = System.getProperty("file.encoding");
    }
    catch (SecurityException e)
    {
      logger.warn("Error accessing system properties.", e);
    }

    // Initialize the locale to the system locale
    try
    {
      if (System.getProperty("jxl.lang")    == null ||
          System.getProperty("jxl.country") == null)
      {
        locale = Locale.getDefault();
      }
      else
      {
        locale = new Locale(System.getProperty("jxl.lang"),
                            System.getProperty("jxl.country"));
      }

      if (System.getProperty("jxl.encoding") != null)
      {
        encoding = System.getProperty("jxl.encoding");
      }
    } 
    catch (SecurityException e)
    {
      logger.warn("Error accessing system properties.", e);
      locale = Locale.getDefault();
    }
  }

这里似乎没有任何问题,我已将编码、本地和显示语言设置为英国特定/兼容的。默认情况下,区域设置已经是英国。

现在对于 WorkbookParser:

public class WorkbookParser extends Workbook
  implements ExternalSheet, WorkbookMethods
{
  /**
   * The logger
   */
  private static Logger logger = Logger.getLogger(WorkbookParser.class);

  /**
   * The excel file
   */
  private File excelFile;
  /**
   * The number of open bofs
   */
  private int bofs;
  /**
   * Indicates whether or not the dates are based around the 1904 date system
   */
  private boolean nineteenFour;
  /**
   * The shared string table
   */
  private SSTRecord sharedStrings;
  /**
   * The names of all the worksheets
   */
  private ArrayList boundsheets;
  /**
   * The xf records
   */
  private FormattingRecords formattingRecords;
  /**
   * The fonts used by this workbook
   */
  private Fonts fonts;

  /**
   * The sheets contained in this workbook
   */
  private ArrayList sheets;

  /**
   * The last sheet accessed
   */
  private SheetImpl lastSheet;

  /**
   * The index of the last sheet retrieved
   */
  private int lastSheetIndex;

  /**
   * The named records found in this workbook
   */
  private HashMap namedRecords;

  /**
   * The list of named records
   */
  private ArrayList nameTable;

  /**
   * The list of add in functions
   */
  private ArrayList addInFunctions;

  /**
   * The external sheet record.  Used by formulas, and names
   */
  private ExternalSheetRecord externSheet;

  /**
   * The list of supporting workbooks - used by formulas
   */
  private ArrayList supbooks;

  /**
   * The bof record for this workbook
   */
  private BOFRecord workbookBof;

  /**
   * The Mso Drawing Group record for this workbook
   */
  private MsoDrawingGroupRecord msoDrawingGroup;

  /**
   * The property set record associated with this workbook
   */
  private ButtonPropertySetRecord buttonPropertySet;

  /**
   * Workbook protected flag
   */
  private boolean wbProtected;

  /**
   * Contains macros flag
   */
  private boolean containsMacros;

  /**
   * The workbook settings
   */
  private WorkbookSettings settings;

  /**
   * The drawings contained in this workbook
   */
  private DrawingGroup drawingGroup;

  /**
   * The country record (containing the language and regional settings)
   * for this workbook
   */
  private CountryRecord countryRecord;

  private ArrayList xctRecords;

  /**
   * Constructs this object from the raw excel data
   *
   * @param f the excel 97 biff file
   * @param s the workbook settings
   */
  public WorkbookParser(File f, WorkbookSettings s)
  {
    super();
    excelFile = f;
    boundsheets = new ArrayList(10);
    fonts = new Fonts();
    formattingRecords = new FormattingRecords(fonts);
    sheets = new ArrayList(10);
    supbooks = new ArrayList(10);
    namedRecords = new HashMap();
    lastSheetIndex = -1;
    wbProtected = false;
    containsMacros = false;
    settings = s;
    xctRecords = new ArrayList(10);
  }

我在这里看不到任何会影响工作簿创建/访问的内容。


再往下看,通过床单和单元格,我发现了两件有趣的事情:

  1. 单元格的格式有这个参数 |valuepositivePrefix|"$" (id=709)
  2. 这个货币正确的。看这个:
    变量形成 Eclipse 调试窗口,将货币显示为 GBP/£

所以我的问题是,当该getContents()方法在单元格上运行时,为什么它不与货币一起返回(给,我想是 £$#####,因为它仍然有 postivePrefix)以及为什么这个的正前缀无论如何都要设置$

我看不到在 src 文档中创建单元格的位置,或者在哪里实现了 getContents() 方法(我发现它是声明),所以我无法进一步挖掘,但我希望其他人知道这个原因问题”,或者至少可以解决?

4

2 回答 2

2

这为我做到了。进行一些设置。使用 WorkbookSettings 作为第二个参数获取工作簿。我认为编码对你来说很重要。

    WorkbookSettings wbs = new WorkbookSettings(); 
    wbs.setExcelRegionalSettings("GB");
    wbs.setExcelDisplayLanguage("GB");
    Locale l = new Locale("en_GB");
    wbs.setLocale(l);
    wbs.setEncoding("ISO8859_1");


    Workbook workbook = Workbook.getWorkbook(new File("experimental-in.xls"), wbs);
于 2016-11-25T00:04:40.660 回答
1

我无法弄清楚为什么会这样。但是,如果您无法修复系统,那就破解它!

对于 100 的单元格“值”,我以下列形式之一获得回报:

  • 100- 普通号码
  • [£$ -42] 100- 前缀货币无法识别
  • 100 [£$ -42]- 后缀货币无法识别
  • "?" 100- 前缀符号不可渲染
  • 100 "?"- 后缀符号不可渲染

因此,我决定cell.getContent()一旦确定我有一个数字,就应该将返回的数字正则表达式。


识别数字格式:

public static boolean isNumberFormat(Cell cell){
    CellType myCellType = cell.getType();
    return myCellType.equals(CellType.NUMBER);
}

使用正则表达式捕获数字

对于上述每个,我得到了正则表达式形式text2re的“样式” ,然后使用debuggex直到我将它们组合起来。这导致了以下regex表达式:

(?:\"..*?\"|\[.*?\])*?\s*(\d+,?\d*?\.\d*)\s*(?:\[..*?]|".*?")*?

这看起来像一场噩梦,但我会分解它,就像我的代码一样:

String digits="(\\d+,?\\d?\\.\\d*)";

一位或多位数字,带有逗号和小数位。

String sbraceGroup="\\[.*?\\]";

匹配用方括号括起来的零个或多个字符的组

String quotationGroup="\"..*?\"";

匹配零个或多个用引号括起来的字符的组

String junk = "(?:"+sbraceGroup+"|"+quotationGroup+")*?";

我们不想要的正则表达式的字符串,用于(?:.....)将其封闭为非匹配组,以及*?不贪婪的零->多匹配。

我现在可以编译我的模式:

Pattern p = Pattern.compile(junk+"\\s*"+digits+"\\s*"+junk,Pattern.CASE_INSENSITIVE | Pattern.DOTALL);

其中\s*是零-> 许多空白字符(制表符、空格等)。

现在一起:

String myCellA1 = myRow[rowCounter].getContents();
String digits="(\\d+,?\\d?\\.\\d*)";    // Non-greedy match on digits
String sbraceGroup="\\[.*?\\]"; //  non-greedy match on square Braces 1
String quotationGroup="\"..*?\""; //    non-greedy match on things in quotes
String junk = "(?:"+sbraceGroup+"|"+quotationGroup+")*?";
Pattern p = Pattern.compile(junk+"\\s*"+digits+"\\s*"+junk,Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
Matcher m = p.matcher(myCellA1);
String match = "";
if (m.find())
{
    match=m.group(1).toString();
}else
{
    match = myCellA1;
}

现在我已经解决了我的问题

于 2013-04-09T10:48:38.613 回答