2

I am trying to use regular expression to search and replace multiple times on a same line. I believe that Regex can do this using either positive lookahead/lookbehind feature.

I have a long list of states and the airports in them. And I am trying to put them all in the State, Aiport pairs, one line at a time.

Here is the input

State, Airports
----------------
Chicago, ORD, MDW
NY, JFK, LGA, EWR
California, LAX, JWA, LGB, BUR

Here is the output.

Chicago, ORD
Chicago, MDW  
NY, JFK
NY, LGA
NY, EWR
California, LAX
California, JWA
California, LGB
California, BUR

Can you please help suggest a regex or any other way to accomplish this? Thank you.

I use Notepad++ for the Regex, but can use any text editor for this.

5
  • 1
    What you are trying to accomplish is practically impossible. While it might be possible with some heavy tweaking, it wouldn't be worth the effort as regex is ill-suited for the task. It isn't designed for this. You need to use an actual programming language to do this. I recommend Python. Jun 1 at 17:43
  • @Ξένη Γήινος: Why do you think it's impossible? OP wants to do this in a text editor.
    – Toto
    Jun 1 at 18:40
  • @Toto A great man once said: First, please put down the chocolate-covered banana and step away from the European currency systems. You might also want to use the right tools for the job, rather than pounding a nail with an old shoe or glass bottle. Jun 1 at 18:50
  • @Ξένη Γήινος: I must say, that Toto has sufficiently and completely answer the question using Regex. I would argue otherwise, that for the workflow of OP, it would rather be a tedious and unproductive process to download/install/learn/run/debug the python script, while the provided solution is suffice. Thanks. Jun 1 at 19:05
  • 1
    With the exception of the Notepad++ regex-replace solution, this could be a good candidate for Code Golf.
    – jcaron
    Jun 5 at 16:52

4 Answers 4

1
  • Ctrl+H
  • Find what: ^(\w+,\h*)(\w+)(?:,\h*(\w+))?(?:,\h*(\w+))?(?:,\h*(\w+))?(?:,\h*(\w+))?(?:,\h*(\w+))?(?:,\h*(\w+))?(?:,\h*(\w+))?(?:,\h*(\w+))?(?:,\h*(\w+))?
  • Replace with: $1$2\n(?3$1$3)(?4\n$1$4)(?5\n$1$5)(?6\n$1$6)(?7\n$1$7)(?8\n$1$8)(?9\n$1$9)
  • TICK Match case
  • TICK Wrap around
  • SELECT Regular expression
  • UNTICK . matches newline
  • Replace all

Explanation:

^               # beginning of line
    (               # group 1
        \w+             # 1 or more word characters
        ,               # a comma
        \h*             # 0 or more horizontal spaces
    )               # end group 1
    (\w+)           # group 2, 1 or more word characters
    (?:             # non capture group
        \h*             # 0 or more horizontal spaces
        (\w+)           # group 3, 1 or more word characters
    )?              # end group, optional
(?:,\h*(\w+))?      # same as above
(?:,\h*(\w+))?      # same as above
(?:,\h*(\w+))?      # same as above
(?:,\h*(\w+))?      # ... 
(?:,\h*(\w+))?      # ... 
(?:,\h*(\w+))?      # ... 
(?:,\h*(\w+))?      # ... 
(?:,\h*(\w+))?      # ... 

Replacement:

$1              # content of group 1
$2              # content of group 2
\n              # line feed, you can use \r\n for Windows
(?3             # if group 3 exists
    $1              # content of group 1
    $3              # content of group 3
)               # endif
(?4\n$1$4)      # same as above
(?5\n$1$5)      # ...
(?6\n$1$6)      # ...
(?7\n$1$7)      # ...
(?8\n$1$8)      # ...
(?9\n$1$9)      # ...

Screenshot (before):

enter image description here

Screenshot (after):

enter image description here

7
  • 1
    Note: this solution is for max 4 comma separated items. A regex isn't viable for this if there are more, otherwise you'll need to make it really really long and convoluted and it'll break once the file content changes and adds more items than the expected maximum.
    – Destroy666
    Jun 1 at 17:53
  • @Toto, this is great. Very complex Regex. Really appreciate you taking time to build it up. It would be greatly beneficial if you can explain it a bit whenever you get a chance. I totally understand, that this can be done using some scripting language, but just REGEX you provided helps a lot. Thank you. Jun 1 at 18:19
  • @Destroy666: This is not a problem, just add as many groups as you want. See my edit
    – Toto
    Jun 1 at 18:37
  • @Toto, Super Awesome. Thank you so much for detailed answer. Keep up the superior work. . Jun 1 at 18:43
  • 1
    "not a problem" is quite subjective because the regex would be hardly readable with e.g. 50 comma separated items.
    – Destroy666
    Jun 1 at 18:43
2

That regex is way too complicated. By using an actual programming language, things will be much simpler.

Here I give an example in Python. Get Python here.

Say you have this input:

Chicago, ORD, MDW
NY, JFK, LGA, EWR
California, LAX, JWA, LGB, BUR

And you want to convert it to your given output:

Chicago, ORD
Chicago, MDW  
NY, JFK
NY, LGA
NY, EWR
California, LAX
California, JWA
California, LGB
California, BUR

It is simple, first split the string into lines, the split each line into list of strings by commas. Finally return the combination of the first element and every other element of the same list.

lines = """Chicago, ORD, MDW
NY, JFK, LGA, EWR
California, LAX, JWA, LGB, BUR"""

for line in lines.splitlines():
    lst = line.split(', ')
    first = lst[0]
    for e in lst[1:]:
        print(f'{first}, {e}')
1

For Notepad++, if you have to use it, you can use PythonScript also:

  1. Plugins -> Plugins Admin... -> Check PythonScript and click Install.
  2. Plugins -> PythonScript -> New Script -> create it in default scripts directory.
  3. Add these contents and save:
import re

def split_text(match):
  # Split by comma and any number of horizontal whitespace
  parts = re.split(',[\t ]*', match.group(1))  
  results = []
  
  # Skip first item and create strings with all the combinations
  for part in parts[1:]:
    results.append("%s, %s"%(parts[0], part))
    
  # Combine all parts with separated by newline
  return "\n".join(results)

# Ensure proper matches and call split_text() handler function
# (?!\A) - don't match start of file (first line)
# [\w\t ,]+ - match only word characters, horizontal whitespace and commas
editor.rereplace('^(?!\A)([\w\t ,]+)$', split_text);

This works with the header and preserves it.

1
1

I know you asked for a regex to use in Notepad++, but here's a perl one-liner anyway:

perl -nle '($state,@f) = split /,\s*/; print "$state, $_" for @f;' < txt

Explanation:

  • perl: invoke perl
  • -n flag: will perform a loop over each line of the input, and execute the code provided for each line
  • -l flag: automatically remove line endings on input and add them to outputs
  • -e flag: use the code provided as argument
  • ($state,@f) = split /,\s*/: split the line anywhere there is a comma, separated by optional white space, put the first value in $state, and the rest in array @f
  • print "$state, $_" for @f: for each item in @f (so each airport), print a line with the state and the airport

Alternative:

perl -F',\s*' -le '$state = shift @F; print "$state, $_" for @F;' < txt
  • -F',\s*' flag: auto-split using the provided separator regex, store the results in @F. Implies -n.
  • $state = shift @F: remove first item from @F and store it in $state

Of course Chicago is not a state :-)

1
  • thank you for an alternative solution. Really appreciate it. Its funny, I read/edited this post few times and did not realize about Chicago/Illinois. Thanks for pointing that out. :) Jun 5 at 16:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .