关闭如何从Scala中的字符串中检测类型?

关闭如何从Scala中的字符串中检测类型?,scala,csv,pattern-matching,string-matching,opencsv,Scala,Csv,Pattern Matching,String Matching,Opencsv,我试图解析csv文件,我需要从字符串值开始确定每个字段的类型 例如: val row: Array[String] = Array("1/1/06 0:00","3108 OCCIDENTAL DR","3","3C","1115") 这就是我将得到的: row(0) --> Date row(1) --> String row(2) --> Int Ecc.... 我该怎么办 ------------------------------------解决方案--------

我试图解析csv文件,我需要从字符串值开始确定每个字段的类型

例如:

val row: Array[String] = Array("1/1/06 0:00","3108 OCCIDENTAL DR","3","3C","1115")
这就是我将得到的:

row(0) --> Date
row(1) --> String
row(2) --> Int
Ecc....
我该怎么办

------------------------------------解决方案------------------------------------

这是我发现的识别字符串、日期、Int、Double和Boolean字段的解决方案。 我希望将来有人能为我服务

  def typeDetection(x: String): String = {
    x match {
      // Matches: [12], [-22], [0] Non-Matches: [2.2], [3F]
      case int if int.matches("^-?[0-9]+$") => "Int"
      // Matches: [2,2], [-2.3], [0.2232323232332] Non-Matches: [.2], [,2], [2.2.2]
      case double if double.matches("^-?[0-9]+(,|.)[0-9]+$") => "Double"
        // Matches: [29/02/2004 20:15:27], [29/2/04 8:9:5], [31/3/2004 9:20:17] Non-Matches: [29/02/2003 20:15:15], [2/29/04 20:15:15], [31/3/4 9:20:17]
      case d1 if d1.matches("^((((31\\/(0?[13578]|1[02]))|((29|30)\\/(0?[1,3-9]|1[0-2])))\\/(1[6-9]|[2-9]\\d)?\\d{2})|(29\\/0?2\\/(((1[6-9]|[2-9]\\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))|(0?[1-9]|1\\d|2[0-8])\\/((0?[1-9])|(1[0-2]))\\/((1[6-9]|[2-9]\\d)?\\d{2})) *(?:(?:([01]?\\d|2[0-3])(\\-|:|\\.))?([0-5]?\\d)(\\-|:|\\.))?([0-5]?\\d)")
        => "Date"
        // Matches: [01.1.02], [11-30-2001], [2/29/2000] Non-Matches: [02/29/01], [13/01/2002], [11/00/02]
      case d2 if d2.matches("^(?:(?:(?:0?[13578]|1[02])(\\/|-|\\.)31)\\1|(?:(?:0?[1,3-9]|1[0-2])(\\/|-|\\.)(?:29|30)\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:0?2(\\/|-|\\.)29\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\\/|-|\\.)(?:0?[1-9]|1\\d|2[0-8])\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$")
        => "Date"
        // Matches: [12/01/2002], [12/01/2002 12:32:10] Non-Matches: [32/12/2002], [12/13/2001], [12/02/06]
      case d3 if d3.matches("^(([0-2]\\d|[3][0-1])(\\/|-|\\.)([0]\\d|[1][0-2])(\\/|-|\\.)[2][0]\\d{2})$|^(([0-2]\\d|[3][0-1])(\\/|-|\\.)([0]\\d|[1][0-2])(\\/|-|\\.)[2][0]\\d{2}\\s([0-1]\\d|[2][0-3])\\:[0-5]\\d\\:[0-5]\\d)$")
        => "Date"
      case boolean if boolean.equalsIgnoreCase("true") || boolean.equalsIgnoreCase("false") => "Boolean"
      case _ => "String"
    }
}

产出:

Date probably
String probably
Int probably
String probably
Int probably
但老实说,我不会使用这种方法,因为这种方法很容易出错,而且有太多可能出错的地方,我甚至都不想去想它,最简单的例子是,如果一个字符串包含一个
/
,那么这一小段代码将匹配为
日期


我不知道您的用例,但根据我的经验,创建一些试图猜测类型形成不安全数据的东西总是一个坏主意,如果您可以控制它,您可以引入一些标识符,例如
“1/1/06 0:00%d%”
其中
%d%
将指示日期等等,然后将其从字符串中删除,即使这样,您也永远不会100%确定这不会失败。

对于每个字符串:尝试将其解析为您想要的类型。您必须为每种类型编写一个函数。继续按顺序尝试,直到其中一个起作用,顺序很重要。您可以使用您最喜欢的日期/时间库

  import java.util.Date
  def stringdetect (s : String) = {
    dateFromString(s) orElse intFromString(s) getOrElse s
  }

  def arrayDetect(row : Array[String]) = row map stringdetect

  def arrayTypes(row : Array[String]) = {
    arrayDetect(row) map { _ match {
      case x:Int => "Int"
      case x:Date => "Date"
      case x:String => "String"
      case _ => "?"
    } }
  }      

  def intFromString(s : String): Option[Int] = {
    try {
      Some(s.toInt)
    } catch {
      case _ : Throwable => None
    }
  }

  def dateFromString(s : String): Option[Date] = {
    try {
      val formatter = new java.text.SimpleDateFormat("d/M/yy h:mm")
      formatter.format(new java.util.Date)
      Some(formatter.parse(s))
    } catch {
      case _ : Throwable => None
    }
  }
从REPL/工作表:

  val row: Array[String] = Array("1/1/06 0:00","3108 OCCIDENTAL DR","3","3C","1115")
        //> row  : Array[String] = Array(1/1/06 0:00, 3108 OCCIDENTAL DR, 3, 3C, 1115)
  arrayDetect(row)
        //> res0: Array[Any] = Array(Sun Jan 01 00:00:00 CST 2006, 3108 OCCIDENTAL DR, 3 , 3C, 1115)
  arrayTypeDisplay(row)
        //> res1: Array[String] = Array(Date, String, Int, String, Int)

您好@ende neu,谢谢您的建议,但正如您所说,这样做有出错的风险。不幸的是,我没有控制输入字段,所以我甚至不能考虑引入任何标识键。没有其他方法(我知道)这样做,一般来说,你需要从字符串中识别出一个类型,你可以使你的比较更严格。例如,如果所有日期的格式都是
1/1/06 0:00
,则可以检查是否有两个
/
和一个
。尽管如此,这永远不会是防弹的,如果你有其他的,甚至可能更复杂的识别类型,它会变得更难。除非绝对正确,否则投票赞成关于这是一个坏主意的警告necessary@EndeNeu我正在寻找一种用正则表达式做任何事情的方法。此外,没有定义日期格式,我可能有任何格式的日期dd/mm/yyyy,yyyy/mm/dd,yyyy/mm/dd hh:mm ecc…--正则表达式是一个很好的工具,但原理和我使用的一样:猜测。事实上,这一行
string.matches(“[0-9]+”)
使用正则表达式来匹配只有数字的字符串。不幸的是,正如Paul之前所说的,除非绝对必要,否则这是一个坏主意。如果您对数据的内容没有期望,您将如何处理数据?如果你事先不知道一个字段是日期、整数还是字符串,一旦你决定了它是什么,你可以用它做什么?Hello@jwg,我正在分析一个CSV文件,里面可能包含任何东西。CSV将由一个拆分器控制,该拆分器将填充一个案例类。我必须识别每个字段的类型,因为我必须将其保存在列级结构中。这是我的选择。。这是我发现自己所处的环境所固有的。但是,一旦将数据存储在表或对象中(如果它仍然是一个字符串,您就不能这样做),您将如何处理这些数据呢?Gagstead感谢您的回答。您的方法可能包含在我的上下文中可重用的内容。这个主意不错,但不适合约会。我需要识别您可以插入首选DateTime库(如JODA)的任何日期格式,但对于示例,我只使用了内置库。在返回字符串之前,您可以检查多种格式,但如果您可以使用诸如“dd-MM-yy”之类的日期,则搜索“/”将不再准确。在某个时刻,你将不得不对你的数据做一些假设。
  val row: Array[String] = Array("1/1/06 0:00","3108 OCCIDENTAL DR","3","3C","1115")
        //> row  : Array[String] = Array(1/1/06 0:00, 3108 OCCIDENTAL DR, 3, 3C, 1115)
  arrayDetect(row)
        //> res0: Array[Any] = Array(Sun Jan 01 00:00:00 CST 2006, 3108 OCCIDENTAL DR, 3 , 3C, 1115)
  arrayTypeDisplay(row)
        //> res1: Array[String] = Array(Date, String, Int, String, Int)