如何正确地将作为 CSV 文件中字符串的浮点数/双精度数作为浮点数/双精度数导入程序?

Posted

技术标签:

【中文标题】如何正确地将作为 CSV 文件中字符串的浮点数/双精度数作为浮点数/双精度数导入程序?【英文标题】:How to properly import a float/double number being a String in a CSV file to a program as float/double? 【发布时间】:2018-12-29 20:02:01 【问题描述】:

简介

我制作了一个简单的程序,它以 .csv 文件格式存储数据,稍后读取以进行绘图。一切都用 Java 完成。

csv 文件中的数据示例如下:

2018/12/29
Tejido,321 908,13.55,43.18,$15.98,
Ropa,195 045,20.55,45.93,$123.01,
Gorra de visera,126 561,17.43,42.32,$79.54,
Cerveza,80 109,3.37,17.93,$12.38,
Mercancías de playa,75 065,11.48,39.73,$105.93,
Bebidas alcohólicas,31 215,4.84,27.90,$32.29,
Artículos de cuero,19 098,23.13,44.09,$198.74,

到目前为止我尝试了什么?

在阅读和研究文档后,我想出了这个非常适合我的问题的解决方案(如果它有效的话......)

public class CSVinput 

public static void main(String[] args) throws FileNotFoundException

    Scanner scan = new Scanner(new File("produccion.csv"));
    scan.useDelimiter(",");
    
    while(scan.hasNext())
    
        String date = scan.next();
        System.out.println(date);
        String name = scan.next();
        System.out.println(name);
        int quantity = Integer.parseInt(scan.next().replaceAll(" ", "."));
        System.out.println(quantity);
        double quality = Double.parseDouble(scan.next());
        System.out.println(quality);
        double realmQ = Double.parseDouble(scan.next());
        System.out.println(realmQ);
        double cost = Double.parseDouble(scan.nextLine());
        System.out.println(cost);
        
        if (scan.hasNextLine())
        
            scan.nextLine();
            System.out.println(date+"," + name+"," + quantity+"," + quality+"," + realmQ+"," + cost);
        
        scan.close();
        
    

    


问题出在哪里?

问题是当我尝试导入字符串数据并将其转换为 double/float 时,它会向我抛出:

Exception in thread "main" java.lang.NumberFormatException: For input 
string: "13.55"

我认为,如果我将其解析为 double 就足够了。

完全异常错误

Exception in thread "main" java.lang.NumberFormatException: For input string: "13.55"
at 

java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at webscraper.CSVinput.main(CSVinput.java:29)
C:\Users\Jonathan\Desktop\WebScraper_03\WebScraper\nbproject\build- 
impl.xml:1339: The following error occurred while executing this line:
C:\Users\Jonathan\Desktop\WebScraper_03\WebScraper\nbproject\build- 
impl.xml:980: Java returned: 1
BUILD FAILED (total time: 1 second)

【问题讨论】:

如果你解析成双精度,你是对的。但是你正在解析成一个 int。 在处理 Money 时,floatdouble 是非常糟糕的选择,因为它们存在数字化错误0.1 在二进制中是一个无穷小部分 i> 无法使用固定数字二进制数存储在计算机中。 哪一行抛出异常?此外,语言环境可能是一个问题,因为我相信 Java 在执行该功能时会考虑到这一点。 【参考方案1】:

如果您调试了代码,您会在第 1 次阅读中发现:

String date = scan.next();
System.out.println(date);

变量 dates 被赋予这个值:

2018/12/29\r\nTejido

从这一点开始,一切都显然是错误的。 当然,一个错误是您尝试读取循环内的日期,但这不是您出现问题的唯一原因。 为什么使用next()? 您应该使用nextLine() 读取文件并用, 分割每一行:

public static void main(String[] args) 
    Scanner scan = null;
    try 
        scan = new Scanner(new File("produccion.csv"));
     catch (FileNotFoundException e) 
        e.printStackTrace();
    

    if (scan == null)
        return;

    if (scan.hasNextLine()) 
        String date = scan.nextLine();
        System.out.println(date);
        while (scan.hasNextLine()) 
            String line = scan.nextLine();
            String[] tokens = line.split(",");

            String name = tokens[0];
            System.out.println(name);

            int quantity = Integer.parseInt(tokens[1].replace(" ", ""));
            System.out.println(quantity);

            double quality = Double.parseDouble(tokens[2]);
            System.out.println(quality);
            double realmQ = Double.parseDouble(tokens[3]);
            System.out.println(realmQ);
            double cost = Double.parseDouble(tokens[4].replace("$", ""));
            System.out.println(cost);

            System.out.println(date + "," + name + "," + quantity + "," + quality + "," + realmQ + "," + cost);
        
        scan.close();
    

从上面的代码可以看出,需要 2 个替换:" """ 用于 "321 908""$""" 的值,例如 "$15.98"

【讨论】:

使用 next 可以在线读取单个令牌,这就是 OP 正在做的事情。它比使用 split 更神秘,但它有效。 我在这里看到的唯一缺陷是数组超出了索引。剩下的就是我想要的。很好的答案,感谢您的宝贵时间。圣诞快乐,新年快乐! @forpas:OP 明确将分隔符设置为“,”,这就是它起作用的原因。 @WhiteGlove 只有当每行不包含样本中的项目数时,数组才能超出索引。所以你可能想检查一下。 @forpas:我做到了。这就是我 my 回答的依据。请不要妄自菲薄地教训我;我只是指出我对此的观察。你的代码也可以工作,但它给已经大部分工作的东西添加了不必要的仪式。【参考方案2】:

我可以看到三个问题:

您正在尝试解析循环内的一次性行。 不要这样做,因为这只会在您回去调试时让您感到困惑。

将该代码移到循环的外部

Scanner scan = new Scanner(new File("produccion.csv"));
scan.useDelimiter(",");
String date = scan.nextLine();
System.out.println(date);
while(scan.hasNext())

在你修复它之后,你正在做一些事情......奇怪使用字符串“321 908”。

int quantity = Integer.parseInt(scan.next().replaceAll(" ", "."));

这表示一个用句点替换空格的字符串,并尝试将其解析为整数。现在这可能取决于您在本机使用的 thousands separator,但默认情况下,Java 使用美国惯例逗号 (",") 作为千位分隔符,句点 (".") 作为小数分隔符。

我无法凭经验回答这个问题,因为你的意图不明确,但至少如果你完全摆脱了空间,你会得到一个 int...

int quantity = Integer.parseInt(scan.next().replaceAll(" ", ""));

您必须对另一个数字前面的美元符号进行处理。您无法使用任何 不是双精度的符号解析双精度,并且货币不是数字的一部分。将其替换为类似于您对数量执行 replaceAll 的方式。

【讨论】:

我想要一个整数。我试图看看它是一个空格还是一些担心我受伤无法将其用作整数的东西。谢谢(你的)信息!圣诞快乐,新年快乐!

以上是关于如何正确地将作为 CSV 文件中字符串的浮点数/双精度数作为浮点数/双精度数导入程序?的主要内容,如果未能解决你的问题,请参考以下文章

浮点数的基数排序

如何在没有不必要的十进制 0 的情况下很好地将浮点数格式化为字符串

如何在 Python 中为 csv.reader 设置语言环境?

如何正确地将纬度和经度坐标插入 mySQL 浮点数?

查找具有相同内部表示的浮点数/双精度数的最小值/最大值

Android - 如何正确地将字符串解析为浮点数(价格数字格式:整数、小数或两者兼有)