string - 如何用另一个 [ELIXIR/ERLANG] 替换字符串中的第 n 个字符
问题描述
如何replace_at
在 Elixir 或 Erlang 中执行字符串?
例如给定这个固定宽度的文件:
EmployeeFundMappingID EmployeeID FundID IsActive EntryDate ExitDate ExitTypeID DateCreated CreatedByID DateModified ModifiedByID ConfirmedBy DateConfirmed GUID IsPooled DatePooled
1 1118544 1 1 2009-04-20 00:00:00.000 NULL NULL 2014-05-17 08:46:48.020 1 2014-10-30 13:34:47.177 NULL 1 2009-04-20 17:48:12.067 NULL NULL NULL
2 1027350 1 1 2008-03-03 00:00:00.000 NULL NULL 2014-05-17 08:46:48.020 1 2014-10-30 13:34:47.177 NULL 1 2008-05-04 15:13:30.303 NULL NULL NULL
3 1024795 1 1 2008-02-29 00:00:00.000 NULL NULL 2014-05-17 08:46:48.020 1 2014-10-30 13:34:47.177 NULL 1 2008-05-04 15:13:30.303 NULL NULL NULL
4 1116497 1 1 2009-03-24 00:00:00.000 NULL NULL 2014-05-17 08:46:48.020 1 2014-10-30 13:34:47.177 NULL 1 2009-03-24 13:00:15.277 NULL NULL NULL
5 1116569 1 1 2009-03-24 00:00:00.000 NULL NULL 2014-05-17 08:46:48.020 1 2014-10-30 13:34:47.177 NULL 1 2009-03-24 14:43:08.280 NULL NULL NULL
6 1116920 1 1 2009-03-27 00:00:00.000 NULL NULL 2014-05-17 08:46:48.020 1 2014-10-30 13:34:47.177 NULL 1 2009-03-27 17:16:35.073 NULL NULL NULL
在 col 位置:
[0, 22, 34, 46, 55, 79, 103, 115, 139, 151, 175, 188, 200, 224, 265, 274]
我们如何在每个 col 位置\s
替换为?\t
我正在有效地尝试将Fixed-Width
文件转换为csv
解决方案
我会用一组改变字符串中各个位置的函数来减少原始行。
funs =
[22, 34, 46, 55, 79, 103, 115, 139, 151, 175, 188, 200, 224, 265, 274]
|> Enum.map(& &1 - 1)
|> Enum.map(fn len ->
fn <<s :: binary-size(len), " ", rest :: binary>> ->
s <> "\t" <> rest
end
end)
input
|> String.trim
|> String.split("\n")
|> Enum.map(fn line ->
Enum.reduce(funs, line, fn fun, acc -> fun.(acc) end)
end)
这可以通过使用生成的宏、每个位置一次和递归调用以更优雅的方式完成,但是在这里减少函数列表对我来说看起来更直接。
这种方法的优点是它会立即在任何不一致的数据上失败,确保(或多或少)如果它通过了,则转换正确完成,这与所有其他较短的解决方案不同。
它也比任何解决方案都快得多Regex
。
由于这将应用于 16M 行,因此这可能是性能最高的版本,它一次匹配整行:
input
|> String.trim
|> String.split("\n")
|> Enum.map(
# [22, 34, 46, 55, 79, 103,
# 115, 139, 151, 175, 188,
# 200, 224, 265, 274]
# note: this assumes the listed positions above are 1-based
fn <<
c1 :: binary-size(21),
" ",
c2 :: binary-size(11),
" ",
c3 :: binary-size(11),
" ",
c4 :: binary-size(8),
" ",
c5 :: binary-size(23),
" ",
c6 :: binary-size(23),
" ",
c7 :: binary-size(11),
" ",
c8 :: binary-size(23),
" ",
c9 :: binary-size(11),
" ",
c10 :: binary-size(23),
" ",
c11 :: binary-size(12),
" ",
c12 :: binary-size(11),
" ",
c13 :: binary-size(23),
" ",
c14 :: binary-size(40),
" ",
c15 :: binary-size(8),
" ",
c16 :: binary
>> ->
c1 <> "\t" <>
c2 <> "\t" <>
c3 <> "\t" <>
c4 <> "\t" <>
c5 <> "\t" <>
c6 <> "\t" <>
c7 <> "\t" <>
c8 <> "\t" <>
c9 <> "\t" <>
c10 <> "\t" <>
c11 <> "\t" <>
c12 <> "\t" <>
c13 <> "\t" <>
c14 <> "\t" <>
c15 <> "\t" <>
c16
end)
推荐阅读
- android - Scrollview 不在新的 androidx 项目中滚动
- ionic4 - 包 .json 文件无法添加 android 平台
- scala - 如何在 play framework2.5 的对象内正确注入 play.api.Configuration?
- c# - 在扩展的 WPF 画布中显示没有文本的 TextBlock
- mongodb - 通过时间戳从 LRS 中获取语句
- excel - 如何通过PowerShell将Excel xlsx文件批量转换为xls文件
- javascript - scope.$watch 不会与散列对象(关联数组)一起触发?
- reactjs - Reactjs 更新状态而不重新加载页面
- java - org.hibernate.LazyInitializationException:未能延迟初始化集合
- svn - 如何在 VisualSVNServer 中为提交后通知设置多个电子邮件目标?