当某些术语之间可能没有空格时,如何拆分一行文本中的项目?
Posted
技术标签:
【中文标题】当某些术语之间可能没有空格时,如何拆分一行文本中的项目?【英文标题】:How do I break apart items in a line of text when there may not be space between some terms? 【发布时间】:2019-07-12 16:21:44 【问题描述】:在 MATLAB 中,我有一段需要拆分的文本。这是此类文本的一个示例:
ROW SHORT-NAME TYPE y1 y2 yRef eq_lhs eq_rhs eq_ref errorCon tolerance isConverged
1 CmpFan.S_Qhx.integ_TmatI +6.3631e+002 +0.0000e+000 +6.3631e+002 TgasPath Tmat TgasPath +1.0000e+000 +1.0000e-004 FALSE DY1I1
2 CmpL.S_Qhx.integ_Tmat I +8.0865e+002 +0.0000e+000 +8.0865e+002 TgasPath Tmat TgasPath +1.0000e+000 +1.0000e-004 FALSE DY2I1
3 CmpH.S_Qhx.integ_Tmat I +1.2874e+003 +0.0000e+000 +1.2874e+003 TgasPath Tmat TgasPath +1.0000e+000 +1.0000e-004 FALSE DY3I1
4 BrnPri.S_Qhx.integ_TmatI +2.8494e+003 +0.0000e+000 +2.8494e+003 TgasPath Tmat TgasPath +1.0000e+000 +1.0000e-004 FALSE DY4I1
5 TrbH.S_Qhx.integ_Tmat I +3.3983e+003 +0.0000e+000 +3.3983e+003 TgasPath Tmat TgasPath +1.0000e+000 +1.0000e-004 FALSE DY5I1
6 TrbL.S_Qhx.integ_Tmat I +2.6320e+003 +0.0000e+000 +2.6320e+003 TgasPath Tmat TgasPath +1.0000e+000 +1.0000e-004 FALSE DY6I1
7 BrnAug.S_Qhx.integ_TmatI +1.6385e+003 +0.0000e+000 +1.6385e+003 TgasPath Tmat TgasPath +1.0000e+000 +1.0000e-004 FALSE DY7I1
8 dep_FanCustomerBleed D +0.0000e+000 +0.0000e+000 +1.0000e-001 CmpFan.CbldAPTMS.WbldFanBleed 0.1 +0.0000e+000 +1.0000e-002 TRUE DY8I1
9 dep_LPCCustomerBleed D +0.0000e+000 +0.0000e+000 +1.0000e-001 CmpL.CbldAPTMS.WbldLPCbleed 0.1 +0.0000e+000 +1.0000e-002 TRUE DY9I1
10 dep_HPCCustomerBleed D +3.0000e+000 +3.0000e+000 +1.0000e-001 CmpH.CbldAPTMS.WbldHPCbleed 0.1 +0.0000e+000 +1.0000e-002 TRUE DY10I1
11 dep_HPCCustomerBleedMidD +0.0000e+000 +0.0000e+000 +1.0000e-001 CmpH.CbldAPTMSmid.WbldHPCmidBleed 0.1 +0.0000e+000 +1.0000e-002 TRUE DY11I1
12 dep_HPXhigh D +2.0000e+002 +2.0000e+002 +2.0000e+002 ShH.HPX HPXhigh HPXhigh +0.0000e+000 +1.0000e-004 TRUE DY12I1
13 dep_HPXlow D +5.0000e+002 +5.0000e+002 +5.0000e+002 ShL.HPX HPXlow HPXlow +0.0000e+000 +1.0000e-004 TRUE DY13I1
14 FlowControl.dep_Tt D +8.6941e+002 +9.2300e+002 +9.2300e+002 Fl_I.Tt Fl_O.Tt FlowControl.Fl_O.Tt-5.8056e-002 +1.0000e-004 FALSE DY14I1
15 FlowControl.dep_Pt D +7.0096e+001 +8.5000e+001 +8.5000e+001 Fl_I.Pt Fl_O.Pt FlowControl.Fl_O.Pt-1.7534e-001 +1.0000e-004 FALSE DY15I1
16 FlowControl.dep_W D +8.0000e-002 +5.4000e-001 +5.4000e-001 Fl_I.W Fl_O.W FlowControl.Fl_O.W-8.5185e-001 +1.0000e-004 FALSE DY16I1
17 MoveCCA.dep_Tt D +1.7141e+003 +1.7310e+003 +1.7310e+003 Fl_I.Tt Fl_O.Tt MoveCCA.Fl_O.Tt-9.7494e-003 +1.0000e-004 FALSE DY17I1
18 MoveCCA.dep_Pt D +7.0096e+002 +6.9900e+002 +6.9900e+002 Fl_I.Pt Fl_O.Pt MoveCCA.Fl_O.Pt+2.8001e-003 +1.0000e-004 FALSE DY18I1
19 MoveCCA.dep_W D +3.4000e+001 +2.2000e+001 +2.2000e+001 Fl_I.W Fl_O.W MoveCCA.Fl_O.W +5.4545e-001 +1.0000e-004 FALSE DY19I1
20 dep_CCAflow D +3.4000e+001 +3.4000e+001 +3.4000e+001 CmpH.B_CCA.WbldCCAflow CCAflow +0.0000e+000 +1.0000e-004 TRUE DY20I1
21 ShH.integrate_Nmech I -2.6321e+003 +0.0000e+000 +2.4194e+004 trqNet 0.0000 trqIn -1.0879e-001 +1.0000e-004 FALSE DY21I1
22 ShL.integrate_Nmech I -5.1547e+003 +0.0000e+000 +3.0562e+004 trqNet 0.0000 trqIn -1.6866e-001 +1.0000e-004 FALSE DY22I1
23 DESIGN_OPR D +5.0176e+001 +5.0000e+001 +5.0000e+001 Overall_PR D_OPR 50.0 +3.5200e-003 +1.0000e-004 FALSE DY23I1
24 DESIGN_T41 D +3.7465e+003 +3.5500e+003 +3.8000e+003 TrbH.Fl_I.Tt D_T41 3800.0 +5.1708e-002 +1.0000e-004 FALSE DY24I1
25 DESIGN_CombinedFanPR D +5.1200e+000 +4.9000e+000 +5.0000e+001 CmpFan.PR*CmpL.PRD_FANPR 50.0 +4.4000e-003 +1.0000e-004 FALSE DY25I1
26 DESIGN_ThirdStreamFlowD +9.9099e-002 +9.2500e-002 +1.3000e-001 ThirdStreamFlowD_ThirdStreamFlow0.13 +5.0762e-002 +1.0000e-004 FALSE DY26I1
27 DESIGN_RMIX D +8.2279e-001 +1.0500e+000 +1.0500e+000 Mixer.RMIX D_RMIX 1.05 -2.1639e-001 +1.0000e-004 FALSE DY27I1
28 DESIGN_Wc D +4.2158e+002 +4.2500e+002 +4.0000e+002 CmpFan.Fl_I.Wc D_WAC 400.0 -8.5534e-003 +1.0000e-004 FALSE DY28I1
每一行都有相同类型的信息,但不幸的是它的产生方式,术语之间不一定有空格。发生这种情况时,很难/不可能知道在哪里拆分术语。我可以在中间丢失一些字符串信息列,但我仍然需要能够以某种方式获取数字。
对于像 13 行这样的东西间隔很好,像下面这样的东西很好用(其中一行存储在变量“txt”中):
>>asCells = textscan(txt,'%d %s %c %f %f %f %s %s %s %f %f %s %s');
>> depTxt = asCells21
depTxt =
'dep_HPXlow'
>> type = asCells3
type =
'D'
>> y1 = asCells4
y1 =
500
>> y2 = asCells5
y2 =
500
>> yRef = asCells6
yRef =
500
>> lhsTxt = asCells71
lhsTxt =
'ShL.HPX'
>> rhsTxt = asCells81
rhsTxt =
'HPXlow'
>> depTxt = asCells91
depTxt =
'HPXlow'
>> err = asCells10
err =
0
>> tol = asCells11
tol =
0.0001
>> if strncmp('TRUE',asCells121,4), conv = 1, else, conv = 0, end
conv =
1
对于像第 11 行这样的东西,因为第一个字符串和字符一起运行,所以根本不工作,抛出格式字符串。同样,它不可能知道“CmpH.CbldAPTMSmid.WbldHPCmidBleed”片段应该被分解为“CmpH.CbldAPTMSmid.Wbld”和“HPCmidBleed”。如果以后有办法仍然获得编号的项目和收敛标志,我会丢失 eq_lhs、eq_rhs 和 eq_ref 信息,但这就是我苦苦挣扎的地方。
我可以像这样抓取第一个字符串(我确实需要保留):
asCells = textscan(txt,'%d %s',1);
>> depTxt = asCells21
depTxt =
'dep_HPCCustomerBleedMidD'
但我不确定如何根据是否进入 TYPE 列有条件地去除最后一个字符。
我注意到所有实际数字都有一个前导加号或减号,并且采用科学计数法(在这种情况下,eq_ref 列中的数字实际上是字符串)。所以我尝试使用正则表达式来获取这样的数值:
>> asCells=regexp(txt,'[+-]\d+\.?\d*([eE][+-]?\d+)?','match','forceCellOutput');
>> y1 = str2double(asCells11)
y1 =
0
>> y2 = str2double(asCells12)
y2 =
0
>> yRef = str2double(asCells13)
yRef =
0.1
>> err = str2double(asCells14)
err =
0
>> tol = str2double(asCells15)
tol =
0.01
这似乎工作正常,但我不知道如何将它与抓住前面的字符串结合起来(特别是需要有条件地去除 I 或 D TYPE 字符)。当基于间距的行中的哪个术语不一致时,我也不确定如何获得收敛标志。我可以正则表达式搜索每行上的字符串 TRUE 或 FALSE 吗?我想我已经很接近了,但我正在为如何将所有部分组合在一起而苦苦挣扎。
【问题讨论】:
你不能用另一种语言编辑这个文本吗? 【参考方案1】:这是一个解决方案,除了 eq_lhs
、eq_rhs
和 eq_ref
之外,您都可以使用。必须执行 2 遍正则表达式,因为我无法从第一遍的前瞻表达式中捕获 TYPE
(也许它可能,但我不太清楚如何......)。
% load data from txt file
fptr = fopen('myData.txt');
s = fread(fptr, inf, 'uint8=>char');
fclose(fptr);
s = s';
% expressions w/named tokens
exprVarType = '(I|D)(?=\s+[+-])';
exprLineStart = '(?<row>\d+)\s+(?<shortName>[^\s]+(?=(\s*I|\s*D|(\s+(I|D)))))+[^+-]+';
exprSciNot1 = '(?<y1>[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)';
exprSciNot2 = '(?<y2>[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)';
exprSciNot3 = '(?<yref>[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)';
exprSciNot4 = '(?<errorCon>[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)';
exprSciNot5 = '(?<tolerance>[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)';
% concatenate regexs
myExpr = strcat(exprLineStart, exprSciNot1, '\s+', exprSciNot2,...
'\s+', exprSciNot3, '[^+-]+', exprSciNot4, '\s+', exprSciNot5, '\s+',...
'(\w+)', '\s+', '([^\r\n]+)');
% first pass: collect all variables except
% 3. Type
% 7. eq_lhs
% 8. eq_rhs
% 9. eq_ref
myData = regexp(s, myExpr, 'names');
% second pass: collect variable type
% couldnt capture this on the first pass because its part of a lookahead
% expression
varType = regexp(s, exprVarType, 'match');
% assign varType to the myData struct
[myData.varType] = deal(varType:);
【讨论】:
在尝试使用您的代码时,我意识到另一个有效的 TYPE 是 C(我认为这是唯一的另一个)。只需快速更改 exprVarType 和 exprLineStart 就可以了。然后我还添加了几行将数字转换为结构中的数字字段而不是字符数组字段。谢谢! 我现在尝试遇到一个新问题。在同一种文件的不同文本块中,代码没有正确处理这一行:31 dep_mixer_total_area D +1.0738e+003 +1.0738e+003 +1.0738e+003 Mixer.Fl_I1.Aphy + Mixer.Fl_I2.AphyMixer.areaMixedDP_MIXEDAREA +0.0000e+000 +1.0000e-004 TRUE DY31I1
这是因为 eq_lhs 表达式中间的加号。关于如何对这种情况进行调整有什么建议吗?我认为它必须类似于在加号(可能还有空格)之后检测非数字字符。
我认为问题在于表达式[^+-]+
我会考虑其他占位符可以放在中间的 3 列中并尽快回复您!以上是关于当某些术语之间可能没有空格时,如何拆分一行文本中的项目?的主要内容,如果未能解决你的问题,请参考以下文章
有没有一种简单的方法可以将由空格字符分隔的一行输入拆分为 C++ 中的整数?