我正在处理一个项目,该项目要求我提取使用pip install命令安装的Python包的名称和位置.

网页包含一个code元素,该元素具有带有bash命令的多行文本.我想写一个JS代码,它可以解析这个文本并找到包及其在文本中的位置.

例如,如果文本为:

$ pip install numpy
pip install --global-option build_ext -t ../ pandas>=1.0.0,<2
sudo apt update
pip uninstall numpy
pip install "requests==12.2.2"

我想要这样的东西:

[
    {
        "name": "numpy",
        "position": 14
    },
    {
        "name": "pandas",
        "position": 65
    },
    {
        "name": "requests",
        "position": 131
    }
]

我怎么能在JavaScript分钟内做到这一点呢?

推荐答案

以下是一个可选的解决方案,try 使用循环而不是正则表达式:

我们的 idea 是找到包含pip install个文本的行,因此它们是我们感兴趣的行.然后,将命令拆分成单词,并循环使用它们,直到我们到达命令的包部分.

首先,我们将定义包的正则表达式.请记住,一个包裹可以是pip install 'stevedore>=1.3.0,<1.4.0' "MySQL_python==1.2.2"个左右:

const packageArea = /(?<=\s|^)["']?(?<package_part>(?<package_name>\w[\w.-]*)([=<>~!]=?[\w.,<>]+)?)["']?(?=\s|$)/;

注意named groups,package_part用来标识"Package with Version"字符串,而package_name用来提取包名.


About the arguments

我们有两种类型的CLI参数:optionsflags.

options的问题是,我们需要理解,下一个单词不是包名,而是option值.

因此,首先我列出了pip install中的所有options命令:

const pipOptionsWithArg = [
  '-c',
  '--constraint',
  '-e',
  '--editable',
  '-t',
  '--target',
  '--platform',
  '--python-version',
  '--implementation',
  '--abi',
  '--root',
  '--prefix',
  '-b',
  '--build',
  '--src',
  '--upgrade-strategy',
  '--install-option',
  '--global-option',
  '--no-binary',
  '--only-binary',
  '--progress-bar',
  '-i',
  '--index-url',
  '--extra-index-url',
  '-f',
  '--find-links',
  '--log',
  '--proxy',
  '--retires',
  '--timeout',
  '--exists-action',
  '--trusted-host',
  '--cert',
  '--client-cert',
  '--cache-dir',
];

然后,我编写了一个函数,稍后将使用该函数来决定当我们看到参数时要做什么:

const handleArgument = (argument, restCommandWords) => {
  let index = 0;
  index += argument.length + 1; // +1 for the space removed by split

  if (argument === '-r' || argument === '--requirement') {
    while (restCommandWords.length > 0) {
      index += restCommandWords.shift().length + 1;
    }
    return index;
  }

  if (!pipOptionsWithArg.includes(argument)) {
    return index;
  }

  if (argument.includes('=')) return index;

  index += restCommandWords.shift().length + 1;
  return index;
};

该函数接收所标识的参数和命令的其余部分,并将其拆分成单词.

(在这里,您将开始看到"索引计数器".因为我们还需要找到每个发现的位置,所以我们需要跟踪原始文本中的当前位置).

在函数的最后几行中,您可以看到我同时处理--option=something--option something.


The Parser

现在,主解析器正在将原始文本拆分成行,然后再拆分成单词.

每个操作都必须更新global index以跟踪我们在文本中的位置,而且,这个索引帮助我们在文本中进行搜索和查找,而不会落入错误的子串,购买indexOf(str, counterIndex):

export const parseCommand = (multilineCommand) => {
  const packages = [];
  let counterIndex = 0;

  const lines = multilineCommand.split('\n');
  while (lines.length > 0) {
    const line = lines.shift();

    const pipInstallMatch = line.match(/pip +install/);
    if (!pipInstallMatch) {
      counterIndex += line.length + 1; // +1 for the newline
      continue;
    }

    const pipInstallLength = pipInstallMatch.index + pipInstallMatch[0].length;
    const argsAndPackagesWords = line.slice(pipInstallLength).split(' ');
    counterIndex += pipInstallLength;

    while (argsAndPackagesWords.length > 0) {
      const word = argsAndPackagesWords.shift();

      if (!word) {
        counterIndex++;
        continue;
      }

      if (word.startsWith('-')) {
        counterIndex += handleArgument(word, argsAndPackagesWords);
        continue;
      }

      const packageMatch = word.match(packageArea);
      if (!packageMatch) {
        counterIndex += word.length + 1;
        continue;
      }

      const startIndex = multilineCommand.indexOf(packageMatch.groups.package_part, counterIndex);
      packages.push({
        type: 'pypi',
        name: packageMatch.groups.package_name,
        version: undefined,
        startIndex,
        endIndex: startIndex + packageMatch.groups.package_part.length,
      });

      counterIndex += word.length + 1;
    }
  }

  return packages;
};

Javascript相关问答推荐

如何用变量productId替换 1"

更改一组用户创建的项目的js排序标准

我可以后增量超过1(最好是内联)吗?

为什么子组件没有在reaction中渲染?

如何分配类型脚本中具有不同/额外参数的函数类型

Cookie中未保存会话数据

我不知道为什么setwritten包装promise 不能像我预期的那样工作

为什么ngModel不能在最后一个版本的Angular 17上工作?'

在这种情况下,如何 for each 元素添加id?

单击ImageListItemBar的IconButton后,在Material—UI对话框中显示图像

setcallback是什么时候放到macrotask队列上的?

禁用.js文件扩展名并从目录导入隐式根index.js时,找不到NodeJS导入模块

当用户点击保存按钮时,如何实现任务的更改?

使用插件构建包含chart.js提供程序的Angular 库?

在JS中动态创建对象,并将其追加到HTML表中

如何利用CSS中的隐藏元素实现平滑扩展和防止网格行间隙

在验证和提交表单后使用useNavigate()进行react 重定向,使用带有加载器和操作的路由

在D3条形图中对具有相同X值的多条记录进行分组

如何找到带有特定文本和测试ID的div?

JWT Cookie安全性