我有这个file.txt.Z
包含这个:
AK2*856*1036~AK3*TD1*4**~AK4*2**1*~AK4*7**1*~AK3*TD5*5**~AK4*3**6*2~AK3*REF*6**~AK4*2**1*~AK3*REF*7**~AK4*2**1*~AK3*REF*8**~AK4*2**1*~AK3*DTM*9**~AK4*2**4*20~AK4*2**4*20~AK3*CTT*12**7~AK5*R
AK2*856*1037~AK3*HL*92**~AK4*3**7*O~AK5*R~AK9*R*2*2*0~SE*25*0001~GE*1*211582~IEA*1*000211582
每条记录都包含几个以标头(通常带有数字)开头的字段AK
,以 . 分隔~
。如果你用~
缩进的换行符替换它,它将显示为:
AK2*856*1036
AK3*TD1*4**
AK4*2**1*
AK4*7**1*
AK3*TD5*5**
AK4*3**6*2
AK3*REF*6**
AK4*2**1*
AK3*REF*7**
AK4*2**1*
AK3*REF*8**
AK4*2**1*
AK3*DTM*9**
AK4*2**4*20
AK4*2**4*20
AK3*CTT*12**7
AK5*R
AK2*856*1037
AK3*HL*92**
AK4*3**7*O
AK5*R
AK9*R*2*2*0
SE*25*0001
GE*1*211582
IEA*1*000211582
每个字段都有由 分隔的子字段*
。例如,子字段AK201
是标题之后的第一个字段AK2
,因此它856
用于示例行。
如您所见,有 2 行的起始字符串为AK2
. 这就像一个行标题,或者我们称之为段标题。中有两个段头file.txt.Z
。我想要的是按顺序从每个段标题中获取这些数据:
所需数据:
- AK202(标题后的第二个字段
AK2
)-AK2*856*this_numeric_value
在星号或~
.之前 - AK301(标题后的第一个字段
AK3
)-~AK3*this_string_value
在*
or之前~
。 - AK502(标题后的第二个字段
AK5
)-~AK5*some_string_value*this_numeric_value
在*
or之前~
。 - AK401(标题后的第一个字段
AK4
)-~AK4*this_numeric_value
在*
or之前~
。 AK4
来自或字段的每个数值AK5
都应始终至少为 2 位。例如 AK502 = 2;AK502 = 02 或 AK401 = 9;AK401 = 09。- 如果没有
AK3
字段,则不输出任何内容。(我已经有一个脚本) - 如果一行包含多个 AK3-AK5-AK4 序列,它们应该与空格连接
- 如果该
AK5
字段在该字段之后丢失,请改为AK3
查找字段。AK4
- 如果字段之后既没有an也
AK4
没有字段,则只输出AK301(AK3头之后的第一个字段)。AK5
AK3
- 如果一个
AK4
字段后有多个AK3
字段,请用逗号连接 AK502-AK401-sequences
输出:
GS: 1036 - TD102,07 TD503 REF02 DTM02,02 CTT
GS: 1037 - HL03
这个怎么做?只要问我你是否对我的问题感到困惑。
编辑:这是我的代码:这是在一个while循环中
while read FILE
do
AK2=`zgrep -oP 'AK2.[\w\s\d]*.\K[\w\s\d]*' < $FILE`
AK3=`zgrep -oP 'AK3.\K[\w\s\d]*' < $FILE`
AK5=`zgrep -oP 'AK5.[\w\s\d]*.\K[\w\s\d]' < $FILE`
AK5_ERROR=`if [[ $AK5 =~ ^[0-9]+$ ]]; then printf "%02d" $AK5 2> /dev/null; else 2> /dev/null; fi`
AK4=`zgrep -oP 'AK4.\K[\w\s\d]*' < $FILE`
AK4_ERROR=`if [[ $AK4 =~ ^[0-9]+$ ]]; then printf "%02d" $AK4 2> /dev/null; else 2> /dev/null; fi`
if [[ $AK3 ]]
then
if $AK5 2> /dev/null
then
echo "GS: $AK2 - $AK3$AK4_ERROR"
else
echo "GS: $AK2 - $AK3$AK5_ERROR"
fi
else
echo "Errors are not specified in the file."
fi
done < file.txt.Z
我的原始代码的问题是它没有连接$AK3
and, $AK5
or $AK4
。
以下 perl 脚本会在给定示例输入时准确生成示例输出。
它可能无法完全按照您对真实数据文件的要求工作,但它并未作为完整的工作解决方案呈现。它作为开始工作的基础 - 玩脚本,弄乱它,破坏它,修复它,改变它来做你想做的事。
毫无疑问,它远非最佳,但如果没有更详细的知识/更好地解释您的输入数据和所需的输出,将很难对其进行改进。
它处理每个输入行(也称为“记录”或使用您的术语的“段”)并构建一个字符串以在处理记录后打印出来。每条输出线都是根据您在问题的“所需数据”部分中的规范构建的。
我保存这个脚本是
mysteryprocess.pl
因为我想不出更合适的名字。然后我用您的示例数据运行它(在一个名为 的文件中input
):示例输出:
那个“REF02 REF03 REF02”让我很困扰,所以这里有另一个版本。这个使用一个数组和一个哈希(
@groups
and%groups
)来构建输出行,另一个哈希(%gseen
)通过记住我们已经看到并包含在输出中的值来防止记录中的重复。组数据存储在 中
%groups
,但哈希在 中是无序的perl
,因此该@groups
数组用于记住我们第一次看到特定组的顺序。顺便说一句,可能应该是数组散列,也就是 HoA(即在每个元素中都包含一个数组的散列),这样可以避免在打印之前
%groups
进行清理(通过使用 perl 的函数而不是简单地附加一个逗号和字符串的新值)。但是我认为这个脚本已经足够复杂了,对于 perl 的新手来说已经足够理解了。$output
join()
使用以下输入
现在的输出是:
笔记:
DTM02,02
也塌陷成刚才DTM02
。消除重复现在发生在所有事情上。我不确定这些更改是否是您想要的。
ps:如果你没有
perl
安装,这段代码很容易翻译成awk
. 这是一个非常简单(甚至简单化)、直接的算法。另一个去,显示一个 awk 版本,正如 cas 建议的那样。可能可以做得更整洁,但无论如何都是一种学习体验。
只需最初在“~”上拆分字段,然后循环遍历每行的所有可用字段。只有当需要一个字段时,才会将其拆分为“*”上的子字段以获取所要求的元素。如果没有找到,'get_slice' 返回 "",所以必须检查。
我想我已经理解了这个问题..