Skip to content

Instantly share code, notes, and snippets.

@gustawdaniel
Last active February 4, 2021 02:58
Show Gist options
  • Save gustawdaniel/afb5a804556c6e90419a438bb0b37359 to your computer and use it in GitHub Desktop.
Save gustawdaniel/afb5a804556c6e90419a438bb0b37359 to your computer and use it in GitHub Desktop.
process_nbp_chf_1984_2020.ts
import fs from 'fs'
interface YearData {
[key: string]: {
col: number,
div: number,
values: { [key: string]: number }[]
}
}
interface OutData {
[key: string]: {
[key: string]: number
}
}
const FILES_FILTER = (e: string, i: number) => i <= Infinity
const ROWS_FILTER = (e: string, i: number) => i <= Infinity
const DROP_SPACES = (l: string): string => l.replace(/\s+/g, '')
const DROP_JUNK_LINES = (l: string): string => l.replace(/(Nr)|(data)|(WALUTA\/CURRENCY)|(\.tab)/ig, '')
const DROP_EMPTY_LINES = (e:string) => !/^,*$/.test(e)
const dict: { [key: string]: string } = {
'W.Brytania': 'CHF'
}
const decomposeBaseSettingsFromNames = (localArr: string[]) => localArr.reduce((p: YearData, n: string, i: number): YearData => {
if (Object.keys(dict).includes(n)) {
p[dict[n]] = { col: i, div: 1, values: [] }
}
return p
}, {})
const decomposeBaseSettingsFromCodes = (localArr: string[]) => localArr.reduce((p: YearData, n: string, i: number): YearData => {
const [, div, curr] = n.match(/^(\d+)(\w+)$/) || []
if (parseInt(div) && curr && Object.values(dict).includes(curr)) {
p[curr] = { col: i, div: parseInt(div), values: [] }
}
return p
}, {})
const getDate = (input: string) => {
if (/^\d{2}\.\d{2}\.\d{4}/.test(input)) {
return input.split('.').reverse().join('-')
}
if (/^\d{2}\/\d{2}\/\d{4}/.test(input)) {
const [m, d, y] = input.split('/')
return [y, m, d].join('-')
}
return false
}
const getDateFromArr = (arr: string[]) => {
return getDate(arr[0]) || getDate(arr[1])
}
const mergeYears = (payload: YearData[]): OutData => {
return payload.reduce((p: OutData, n: YearData) => {
Object.keys(n).forEach(key => {
if (p.hasOwnProperty(key)) {
p[key] = {...p[key], ...n[key].values.reduce((p,n) => ({...p,...n}))}
} else {
p[key] = n[key].values.reduce((p,n) => ({...p,...n}))
}
})
return p
}, {})
}
const main = () => {
const rawDir = process.cwd() + `/raw`
return mergeYears(fs.readdirSync(rawDir).filter(f => f.endsWith('csv'))
.filter(FILES_FILTER)
.map((name, i) => {
const arr = fs
.readFileSync(`${rawDir}/${name}`)
.toString()
.split(`\n`)
.map(DROP_SPACES)
.map(DROP_JUNK_LINES)
.filter(DROP_EMPTY_LINES)
.filter(ROWS_FILTER)
.map(l => l.split(',').map(DROP_SPACES))
const head = arr.shift()
if (!head) throw Error('File do not have header line.')
let settings: YearData = decomposeBaseSettingsFromNames(head)
if (Object.keys(settings).length) {
const subHead = arr.shift()
if (!subHead) throw Error('File do not have sub-header line.')
Object.keys(settings).forEach(key => {
settings[key].div = parseInt(subHead[settings[key].col])
})
} else {
settings = decomposeBaseSettingsFromCodes(head)
}
arr.forEach(localArr => {
const date = getDateFromArr(localArr)
if (typeof date === 'string') {
Object.keys(settings).forEach(key => {
settings[key].values.push({ [date]: parseFloat(localArr[settings[key].col]) / settings[key].div })
})
}
})
return settings
}))
}
fs.writeFileSync(process.cwd() + '/chf.json', JSON.stringify(main()))
console.dir(main(), {depth: Infinity, maxArrayLength: Infinity})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment