in reply to Selecting HL7 Transactions

My first comment would be that you should check out Net::HL7, either to use it directly or to study its mysteries.   “Do Not Do A Thing Already Done.™”

Second, the HL7 format is designed to be simple:   it is “pipe-delimited,” therefore a simple split() can be used to break up each string, and the parameters are positional.

Now reaching down a level to the core problem itself ... this sort of thing is most-easily handled by finite-state machine (FSM) techniques.   Each HL7 transaction starts with a known group, such as MSH in this case, and ends either with a known terminator group or the start of the next group.   A state-machine might therefore start in a SKIP_FOR_MSH state, whereupon it empties a list, pushes the current record onto it, and switches, say, to SKIP_FOR_PV1 which is pushing strings until it encounters a PV1 or another MSH (the latter meaning that PV1 is not there).   Now, it sees if the group is missing.   If not, this message is uninteresting and we revert to SKIP_FOR_MSH state.   Otherwise we switch to COLLECT_BAD_TXN and I think you can take it from here.

This logic is simplified by writing the main loop in such a way that you can process the same record twice, so that you can, if you want to, stash the MSH record, switch to SKIP_FOR_MSH state, and know that the just-stashed record will be the next record seen in that state.

Lest your eyes glaze over, go to and search for “FSM.”   Do Not Do A Thing Already Done.™