从 cli 中获取多个模式。参数解析 Python3

Take multiple patterns from cli. argparse Python3

我有一个 python 版本的 grep,我正在为一项任务构建它。我希望我的 python 模块从命令行获取多种模式,就像 grep 一样。然而,无论我做什么,我的 'debug' 论点总是会发生冲突。

这是当前命令行(使用 -h)的样子:

pgreper.py [-h] [--debug] pattern

目前我只能用一种模式搜索:

cat input.txt | ./pgreper.py "were"

我希望能够像这样使用多种模式搜索 input.txt 文件:

cat input.txt | ./pgreper.py "were" "you"

然而,当我尝试这样做时,出现以下错误:

pgreper.py: error: unrecognized argument: you

我知道这与我通过阅读sys.argv[1]生成一个搜索模式有关。我将如何编辑我的脚本,以允许它从 sys.argv 中获取多个模式,而不影响我已经实现的可选参数?

非常感谢:)

ps请无视我的评论,谢谢

#!/usr/bin/python3

import sys
import re
import time
import datetime
import inspect
import argparse

parser = argparse.ArgumentParser(description='Python Grep.')
parser.add_argument('--debug', default='debug', action='store_true', help='Print debug messages')
parser.add_argument('pattern', type=str, help='Pattern for pgrepping')
args = parser.parse_args()


class CodeTrace(object):
    def __init__(self, line, pattern):
        self.line = line
        self.pattern = pattern

    # @staticmethod
    def trace(self, line, pattern):
        # Creating Timestamp
        ts = time.time()
        # Formatting Timestamp
        ts = datetime.datetime.fromtimestamp(ts).strftime('[%Y-%m-%d %H:%M:%S:%f]')
        stack = inspect.stack()
        # Retrieve calling class information
        the_class = stack[1][0].f_locals["self"].__class__
        # Retrieve calling method information
        the_method = stack[1][0].f_code.co_name
        the_variables = stack[1][0].f_code.co_varnames
        # Formats the contents of the debug trace into a readable format,
        # Any parameters passed to the method and the return value, are included in    the debug trace
        debug_trace = ("{} {}.{}.{} {} {} ".format(ts, str(the_class), the_method, the_variables, pattern, line))
        # Send out the debug trace as a standard error output
        sys.stderr.write(debug_trace + "\n")


class Grepper(object):
    def __init__(self, pattern):
        self.pattern = pattern

    # @CodeTrace.trace()
    def matchline(self, pattern):
        regex = re.compile(self.pattern)
        for line in sys.stdin:
            if regex.search(line):
                sys.stdout.write(line)
                if args.debug != 'debug':
                    (CodeTrace(line, pattern).trace(line, pattern))


def main():
    pattern = str(sys.argv[1])
    print(sys.argv)
    Grepper(pattern).matchline(pattern)

if __name__ == "__main__":
    main()    

您的 argparse 参数配置不正确。这就是现在配置参数的方式。检查 argparse 的 Python 文档,因为那里有一个很好的例子。

格式应始终是 yourscript.py -aARGUMENTVAL -bARGUMENTVAL ...etc. -a 和 -b 样式很重要。

您的代码经过编辑,以便更好地应用下面的 argparse 模块。看看这是否更好(没有用于调试的操作参数):

import sys
import re
import time
import datetime
import inspect
import argparse

parser = argparse.ArgumentParser(description='Python Grep.')
parser.add_argument('-p', '--pattern', type=str, help='Pattern for pgrepping')
parser.add_argument('-d','--debug', type=str, default="false", help='Print debug messages')
args = vars(parser.parse_args());


class CodeTrace(object):
    def __init__(self, line, pattern):
        self.line = line
        self.pattern = pattern

    # @staticmethod
    def trace(self, line, pattern):
        # Creating Timestamp
        ts = time.time()
        # Formatting Timestamp
        ts = datetime.datetime.fromtimestamp(ts).strftime('[%Y-%m-%d %H:%M:%S:%f]')
        stack = inspect.stack()
        # Retrieve calling class information
        the_class = stack[1][0].f_locals["self"].__class__
        # Retrieve calling method information
        the_method = stack[1][0].f_code.co_name
        the_variables = stack[1][0].f_code.co_varnames
        # Formats the contents of the debug trace into a readable format,
        # Any parameters passed to the method and the return value, are included in    the debug trace
        debug_trace = ("{} {}.{}.{} {} {} ".format(ts, str(the_class), the_method, the_variables, pattern, line))
        # Send out the debug trace as a standard error output
        sys.stderr.write(debug_trace + "\n")


class Grepper(object):
    def __init__(self, pattern):
        self.pattern = pattern

    # @CodeTrace.trace()
    def matchline(self, pattern):
        regex = re.compile(self.pattern)
        for line in sys.stdin:
            if regex.search(line):
                sys.stdout.write(line)
                if args.debug != 'debug':
                    (CodeTrace(line, pattern).trace(line, pattern))


def main():
    pattern = str(args['pattern'])
    print(sys.argv)
    Grepper(pattern).matchline(pattern)

if __name__ == "__main__":
    main()

您可以提供逗号分隔的字符串来分隔模式`-p"were,you"。使用 python 强大的字符串函数

pattern = ((args['pattern']).replace(" ", "")).split(",");

上面会列出要查找的模式吗?

您可以告诉 argparse 期望 1 个或多个参数,使用 nargs keyword argument:

parser.add_argument('patterns', type=str, nargs='+', help='Pattern(s) for pgrepping')

这里+表示1个或更多。然后您可以组合这些模式:

pattern = '|'.join(['(?:{})'.format(p) for p in args.patterns])

并将其传递给您的 grepper。这些模式在首先被放入非捕获组 ((?:...)) 后与 | 组合,以确保每个模式都被视为不同的。

我会将所有参数解析放在 main() 函数中:

def main():
    parser = argparse.ArgumentParser(description='Python Grep.')
    parser.add_argument('--debug', action='store_true', help='Print debug messages')
    parser.add_argument('pattern', type=str, nargs='+', help='Pattern(s) for pgrepping')
    args = parser.parse_args()

    pattern = '|'.join(['(?:{})'.format(p) for p in args.pattern])
    Grepper(pattern, args.debug).matchline()

我还删除了 --debug 选项的默认值;使用 store_true 意味着它将默认为 False;然后您可以简单地测试 args.debug 是否正确。

你不需要两次传入patternGrepper();您可以在整个 matchline 方法中简单地使用 self.pattern。相反,我也会将 args.debug 传递给 Grepper()(不需要它是全局的)。

参数解析的快速演示,包括帮助消息:

>>> import argparse
>>> parser = argparse.ArgumentParser(description='Python Grep.')
>>> parser.add_argument('--debug', action='store_true', help='Print debug messages')
_StoreTrueAction(option_strings=['--debug'], dest='debug', nargs=0, const=True, default=False, type=None, choices=None, help='Print debug messages', metavar=None)
>>> parser.add_argument('pattern', type=str, nargs='+', help='Pattern(s) for pgrepping')
_StoreAction(option_strings=[], dest='pattern', nargs='+', const=None, default=None, type=<type 'str'>, choices=None, help='Pattern(s) for pgrepping', metavar=None)
>>> parser.print_help()
usage: [-h] [--debug] pattern [pattern ...]

Python Grep.

positional arguments:
  pattern     Pattern(s) for pgrepping

optional arguments:
  -h, --help  show this help message and exit
  --debug     Print debug messages
>>> parser.parse_args(['where'])
Namespace(debug=False, pattern=['where'])
>>> parser.parse_args(['were'])
Namespace(debug=False, pattern=['were'])
>>> parser.parse_args(['were', 'you'])
Namespace(debug=False, pattern=['were', 'you'])
>>> parser.parse_args(['--debug', 'were', 'you'])
Namespace(debug=True, pattern=['were', 'you'])

模式看起来像这样:

>>> args = parser.parse_args(['were', 'you'])
>>> args.pattern
['were', 'you']
>>> pattern = '|'.join(['(?:{})'.format(p) for p in args.pattern])
>>> pattern
'(?:were)|(?:you)'

如果您希望 所有 模式匹配,则需要更改 Grepper() 以获取多个模式并测试所有这些模式。使用 all() function 提高效率(只测试所需数量的模式):

def main():
    parser = argparse.ArgumentParser(description='Python Grep.')
    parser.add_argument('--debug', action='store_true', help='Print debug messages')
    parser.add_argument('pattern', type=str, nargs='+', help='Pattern(s) for pgrepping')
    args = parser.parse_args()

    Grepper(args.pattern, args.debug).matchline()

并且 Grepper class 变为:

class Grepper(object):
    def __init__(self, patterns, debug=False):
        self.patterns = [re.compile(p) for p in patterns]
        self.debug = debug

    def matchline(self, debug):
        for line in sys.stdin:
            if all(p.search(line) for p in self.patterns):
                sys.stdout.write(line)
                if self.debug:
                    CodeTrace(line, self.patterns).trace(line)

CodeTrace class.

进行适当调整