Как мне регулярное выражение разделить на пробел, избегая пробелов в апострофах? - PullRequest
1 голос
/ 03 марта 2020

Я хочу, чтобы "git log --format='(%h) %s' --abbrev=7 HEAD" было разбито на

[
  "git", 
  "log",
  "--format='(%h) %s'",
  "--abbrev=7",
  "HEAD"
]

Как этого добиться, не разбивая пробел в пределах --format='(%h) %s'?

Приветствуются ответы на любом языке: )

Ответы [ 3 ]

2 голосов
/ 03 марта 2020

Как часто в жизни, у вас есть выбор.


  1. Используйте выражение, которое соответствует и захватывает различные части. Это может быть объединено с функцией замены, как в

    import re
    string = "git log --format='(%h) %s' --abbrev=7 HEAD"
    
    rx = re.compile(r"'[^']*'|(\s+)")
    
    def replacer(match):
        if match.group(1):
            return "#@#"
        else:
            return match.group(0)
    
    string = rx.sub(replacer, string)
    parts = re.split('#@#', string)
    #                 ^^^ same as in the function replacer
    
  2. Вы можете использовать лучший regex модуль с (*SKIP)(*FAIL) :

    import regex as re
    string = "git log --format='(%h) %s' --abbrev=7 HEAD"
    
    rx = re.compile(r"'[^']*'(*SKIP)(*FAIL)|\s+")
    parts = rx.split(string)
    
  3. Напишите себе маленький парсер:

    def little_parser(string):
        quote = False
        stack = ''
    
        for char in string:
            if char == "'":
                stack += char
                quote = not quote
            elif (char == ' ' and not quote):
                yield stack
                stack = ''
            else:
                stack += char
    
        if stack:
            yield stack
    
    for part in little_parser(your_string):
        print(part)
    



Все три приведут к
['git', 'log', "--format='(%h) %s'", '--abbrev=7', 'HEAD']
1 голос
/ 03 марта 2020

Как я понимаю, идея состоит в том, чтобы разбить строку на смежные пробелы, за исключением случаев, когда пробелы являются частью подстроки, заключенной в одинарные кавычки. Я верю, что это сработает:

/(?:[^ ']*(?:'[^']+')?[^ ']*)*/

, но приглашаю читателей тщательно его изучить.

demo

Это регулярное выражение можно сделать самостоятельно -документирование, написав его в режиме свободного пробега :

/
(?:         # begin a non-capture group
  [^ ']*    # match 0+ chars other than spaces and single quotes
  (?:       # begin non-capture group
    '[^']+' # match 1+ chars other than single quotes, surrounded
            # by single quotes 
  )?        # end non-capture group and make it optional
  [^ ']*    # match 0+ chars other than spaces and single quotes
)*          # end non-capture group and execute it 0+ times
/x          # free-spacing regex definition mode

Очевидно, что это не будет работать, если есть вложенные одинарные кавычки.

@n.'pronouns ' м. предложил альтернативное регулярное выражение, которое также работает:

/([^ "']|'[^'"]*')*/

демо

0 голосов
/ 03 марта 2020

Я нашел одно возможное (хотя и некрасивое) решение в python (которое также работает с "):

>>> import re
>>> foo = '''git log --format='(%h) %s' --foo="a b" --bar='c d' HEAD'''
>>> re.findall(r'''(\S*'[^']+'\S*|\S*"[^"]+"\S*|\S+)''', foo)
['git', 'log', "--format='(%h) %s'", '--foo="a b"', "--bar='c d'", 'HEAD']

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...