2014-05-14 2 views
2

저는 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.... 

내가 어떻게 할 수 있습니까?

------------------------------------ 해결책 ------- -----------------------------

이것은 String, Date, 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" 
    } 

}

+1

다음 REPL/워크 시트에서

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 } } 

? IOW, 필드가 날짜, int 또는 문자열인지 여부를 미리 알지 못하면 그 데이터를 사용하기 위해 무엇을 사용할 수 있습니까? – jwg

+0

Hello @jwg, 내부에있는 내용이 포함 된 CSV 파일을 분석 중입니다. CSV는 사례 클래스를 채울 분할기로 이동합니다. 필자는 각 열의 구조를 열 수준 구조로 저장해야하기 때문에 각 필드의 형식을 인식해야합니다. 그것은 내가 선택한 자신의 상황에 내재하는 고유 한 선택입니다. – YoBre

+1

그러나 테이블이나 개체에 저장 한 데이터로 무엇을하고 있습니까? 여전히 문자열 인 경우에는 할 수 없었습니다. – jwg

답변

2
val row: Array[String] = Array("1/1/06 0:00","3108 OCCIDENTAL DR","3","3C","1115") 

val types: Array[String] = row.map(x => x match { 
    case string if string.contains("/") => "Date probably" 
    case string if string.matches("[0-9]+") => "Int probably" 
    case _ => "String probably" 
}) 


types.foreach(x => println(x)) 

출력 :

Date probably 
String probably 
Int probably 
String probably 
Int probably 

그러나 모든 정직에서 나는이 방법을 사용하지 않을

는,이 때문에 오류가 발생하기 쉬운이며 갈 수있는 많은 것들이 있습니다 잘못된 생각을하고 싶지도 않은데 가장 단순한 예제는 문자열에 /이 포함되어있는 경우 작은 코드 조각이 Date과 일치한다는 것입니다.

당신의 유스 케이스에 대해 잘 모르겠지만, 제 경험을 통해 유형이 안전하지 않은 데이터를 추측하려고 시도하는 것을 만드는 것이 좋지 않을 수도 있습니다. 제어 할 수 있다면 어떤 식별자를 도입 할 수 있습니다 (예 : "1/1/06 0:00 %d%"). %d%은 날짜 등을 표시 한 다음 문자열에서 해당 날짜를 제거하므로 결코 실패하지 않을 것입니다.

+0

hello @ ende-neu, 귀하의 제안에 감사하지만 말한대로, 이런 식으로 오류가 발생할 위험이 있습니다. 불행히도 나는 입력 필드를 제어 할 수 없기 때문에 식별 키를 도입 할 가능성을 고려조차 할 수 없다. – YoBre

+0

이 작업을 수행하는 다른 방법은 없습니다. 일반적으로 문자열에서 유형을 식별 할 수있는 뭔가가 필요합니다. 예를 들어 모든 날짜가이 형식 인 경우와 같이 비교를 좀 더 엄격하게 만들 수 있습니다. '1/1/06 0 : 00' 두 개의'/'와':'가 있는지 확인할 수 있습니다. 아직도, 이것은 절대 방탄하지 않을 것이며, 유형을 식별하기위한 다른, 어쩌면 더 복잡한 유형이 있다면 더 어려워 질 것입니다. –

+1

절대적으로 필요한 경우가 아니면 나쁜 생각에 대한 경고를받습니다. –

0

각 문자열에 대해 원하는 유형으로 분석해보십시오. 각 유형에 대한 함수를 작성해야합니다. 그들 중 하나가 작동 할 때까지 순서대로 노력하고 주문이 중요합니다. 좋아하는 날짜/시간 라이브러리를 사용할 수 있습니다. 당신은 당신이 그 내용을 더 기대가없는 경우 데이터가 무슨 말을하는 건가요

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) 
+0

갱스 터드 답변 해 주셔서 감사합니다. 귀하의 접근 방식은 내 맥락에서 재사용 가능한 것을 포함 할 수도 있습니다. 아이디어는 좋지만 날짜에는 좋지 않습니다. 어떤 날짜 형식인지 알아야합니다. – YoBre

+0

원하는 DateTime 라이브러리 (예 : JODA)를 연결할 수 있지만 예제에서는 방금 내장 된 라이브러리를 사용했습니다. String으로 되돌아 가기 전에 여러 형식을 검사 할 수 있지만 "dd-MM-yy"와 같은 날짜를 사용할 수있는 경우 "/"를 검색하면 더 이상 정확하지 않습니다. 어느 시점에서 데이터에 대해 몇 가지 가정을 할 것입니다. – Gangstead

관련 문제