I prefer to solve such problems using a Finite-State Machine (FSM) algorithm, because it represents a generalized and easily-adaptable approach to the problem.
For example, from an initial state (that is to say, “while not in final state ...”), you read a line and have one of three possibilities: end-of-file, a blank string, or not-all-blanks. That would lead to final, skip_blanks, or first_string. And so on. The FSM can be drawn out on a piece of paper as the WikiPedia article describes. When you determine (on paper) that the graph is entirely correct, the programming is a snap.
Since the FSM graph can be tricky to correctly design, I suggest that you build a test-suite using e.g. Test::Most to prove that it works as intended in all cases.