使用应用程序语言(最好是批处理脚本)拆分出现次数可变的字符串
Posted
技术标签:
【中文标题】使用应用程序语言(最好是批处理脚本)拆分出现次数可变的字符串【英文标题】:Split string with variable number of occurances using an application language (Batch script preferably) 【发布时间】:2020-01-06 06:38:39 【问题描述】:我有一个包含冒号分隔行的文本文件,如下所示:
OK-10:Jason:Jones:ID No:00000000:male:my notes
OK-10:Mike:James:ID No:00000001:male:my notes OZ-09:John:Rick:ID No:00000002:male:my notes
OK-08:Michael:Knight:ID No:00000004:male:my notes2 OK-09:Helen:Rick:ID No:00000005:female:my notes3 OZ-10:Jane:James:ID No:00000034:female:my notes23 OK-09:Mary:Jane:ID No:00000023:female:my notes46
请注意,并非所有行都有相同数量的术语。我希望每一行都像第一行一样,即只有七个词。对于超出的线路,应形成一条新线路。新行分隔符为O&-
,其中&
只能是Z
或K
。所以上面的预期输出是:
OK-10:Jason:Jones:ID No:00000000:male:my notes
OK-10:Mike:James:ID No:00000001:male:my notes
OZ-09:John:Rick:ID No:00000002:male:my notes
OK-08:Michael:Knight:ID No:00000004:male:my notes2
OK-09:Helen:Rick:ID No:00000005:female:my notes3
OZ-10:Jane:James:ID No:00000034:female:my notes23
OK-09:Mary:Jane:ID No:00000023:female:my notes46
有人可以建议一种使用文本编辑工具、正则表达式或应用程序语言(例如(最好)批处理脚本、Java 或 Python)的方法吗?
更新
我尝试使用 python 和答案中提供的正则表达式代码:
导入 csv 重新导入
with open('form.csv') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for row in csv_reader:
matches = re.findall(r'O[KZ]-\d+:(?:[^:]+:)5.*?(?= O[KZ]|$)', row[29])
print(matches)
但如果一个单元格包含多个条目,例如:
OK-10:Mike:James:ID No:00000001:male:my notes OZ-09:John:Rick:ID No:00000002:male:my notes
它只返回其中的第一个。
【问题讨论】:
我编辑了您的问题,但措辞仍然错误。我希望您能在这里 +1 获得帮助。 【参考方案1】:如果您认为将来可能有其他文件操作任务会受益于通用正则表达式文本处理实用程序,那么您可以考虑JREPL.BAT。它是纯脚本(JScript/batch),可以在 XP 以后的任何 Windows 机器上运行 - 不需要第 3 方 exe 文件。
jrepl "((?:[^:]*:)6.*?) (?=O[KZ]-)" "$1\r\n" /xseq /f "yourFile.txt" /o -
假设O[KZ]-
没有出现在每个逻辑行的开头以外的任何地方,那么您应该能够摆脱这个更简单的正则表达式:
jrepl "\s+(?=O[KZ]-)" "\r\n" /xseq /f "yourFile.txt" /o -
JREPL 中内置了完整文档,可通过jrepl /?
或jrepl /??
获得分页帮助。所有选项的摘要可通过jrepl /?options
获得,所有类型的帮助摘要可通过jrepl /?help
获得。
【讨论】:
【参考方案2】:就这么简单:
@echo off
setlocal EnableDelayedExpansion
for /F %%a in ('copy /Z "%~F0" NUL') do (set CRLF=%%a^
%Do not remove this line%
)
(for %%n in ("!CRLF!") do for /F "delims=" %%a in (input.txt) do (
set "line=%%a"
for %%d in (Z K) do set "line=!line: O%%d-=%%~nO%%d-!"
echo(!line!
)) > output.txt
【讨论】:
【参考方案3】:这是 Python 中基于正则表达式的解决方案,似乎运行良好:
with open('form.csv', 'r') as file:
inp = file.read().replace('\n', '')
matches = re.findall(r'O[KZ]-\d+:(?:[^:]+:)5.*?(?= O[KZ]|$)', inp)
print(matches)
打印出来:
['OK-10:Mike:James:ID No:00000001:male:my notes',
'OK-08:Michael:Knight:ID No:00000004:male:my notes2',
'OK-09:Helen:Rick:ID No:00000005:female:my notes3',
'OZ-10:Jane:James:ID No:00000034:female:my notes23',
'OK-09:Mary:Jane:ID No:00000023:female:my notes46']
以下是正则表达式模式工作原理的简要总结:
O[KZ]-\d+: match the first OK/OZ-number term
(?:[^:]+:)5 then match the next five : terms
.*?(?= O[KZ]|$) finally match the remaining sixth term
until seeing either OK/OZ or the end of the input
我的脚本生成的输出是一个列表,然后您可以将其写回文本文件,以便稍后导入 mysql。请注意,我们在开始时将整个文件读入单个字符串变量。这是使用这种正则表达式方法所必需的。
【讨论】:
谢谢,我对python一无所知,所以我必须搜索如何使用您的解决方案打开csv更新它并保存它以进行测试。 您所要做的就是将文本文件读入 Python,使用我的脚本,然后将列表写回,每行一个条目,仅此而已。 是的,我现在正在看一些教程,是时候接触 python 了:) 我会在测试时回来。再次感谢您的帮助 @netdev 如果您想使用我的答案,您必须将整个文件读入单个字符串变量。逐行迭代根本不起作用,q.v。我更新的答案。以上是关于使用应用程序语言(最好是批处理脚本)拆分出现次数可变的字符串的主要内容,如果未能解决你的问题,请参考以下文章