Rumah > Soal Jawab > teks badan
Saya sedang mengusahakan projek yang memerlukan saya mengekstrak nama dan lokasi pakej Python yang dipasang menggunakan arahan pip install
.
Halaman web mengandungi elemen code
yang mengandungi berbilang baris teks dan arahan bash. Saya ingin menulis kod JS yang boleh menghuraikan teks ini dan mencari pakej dan lokasinya dalam teks.
Sebagai contoh, jika teks ialah:
$ 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"
Nak dapat result macam ni:
[ { "name": "numpy", "position": 14 }, { "name": "pandas", "position": 65 }, { "name": "requests", "position": 131 } ]
Bagaimana saya boleh melaksanakan fungsi ini dalam JavaScript?
P粉7736596872023-09-08 15:53:55
Anda boleh lihat kod yang saya jelaskan dalam jawapan ini.
Berikut ialah satu lagi penyelesaian yang serupa, lebih berdasarkan ungkapan biasa:
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 optionWithArgRegex = `( (${pipOptionsWithArg.join('|')})(=| )\S+)*`; const options = /( -[-\w=]+)*/; const packageArea = /["']?(?<package_part>(?<package_name>\w[\w.-]*)([=<>~!]=?[\w.,<>]+)?)["']?(?=\s|$)/g; const repeatedPackages = `(?<packages>( ${packageArea.source})+)`; const whiteSpace = / +/; const PIP_COMMAND_REGEX = new RegExp( `(?<command>pip install${optionWithArgRegex}${options.source})${repeatedPackages}`.replaceAll(' ', whiteSpace.source), 'g' ); export const parseCommand = (command) => { const matches = Array.from(command.matchAll(PIP_COMMAND_REGEX)); const results = matches.flatMap((match) => { const packagesStr = match?.groups.packages; if (!packagesStr) return []; const packagesIndex = command.indexOf(packagesStr, match.index + match.groups.command.length); return Array.from(packagesStr.matchAll(packageArea)) .map((packageMatch) => { const packagePart = packageMatch.groups.package_part; const name = packageMatch.groups.package_name; const startIndex = packagesIndex + packagesStr.indexOf(packagePart, packageMatch.index); const endIndex = startIndex + packagePart.length; return { type: 'pypi', name, version: undefined, startIndex, endIndex, }; }) .filter((result) => result.name !== 'requirements.txt'); }); return results; };
P粉1945410722023-09-08 10:50:01
Berikut ialah penyelesaian alternatif, cuba gunakan gelung dan bukannya ungkapan biasa:
Ideanya adalah untuk mencari baris yang mengandungi pip install
teks, ini adalah baris yang kami minati. Kemudian, pecahkan perintah itu kepada perkataan dan gelung di atasnya sehingga anda mencapai bahagian pakej arahan itu.
Pertama, kami akan menentukan ungkapan biasa untuk pakej. Ingat, pakej boleh jadi seperti 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|$)/;
Perhatikan pengelompokan bernama , package_part
用于识别“带版本的包”字符串,而 package_name
digunakan untuk mengekstrak nama pakej.
Kami mempunyai dua jenis argumen baris arahan: pilihan dan bendera.
Masalah denganpilihan ialah kita perlu memahami bahawa perkataan seterusnya bukanlah nama pakej, tetapi nilai pilihan.
Jadi, saya mula-mula menyenaraikan semua pilihan dalam arahan pip install
:
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', ];
Saya kemudian menulis fungsi yang akan saya gunakan kemudian untuk memutuskan perkara yang perlu dilakukan apabila ia melihat hujah:
const handleArgument = (argument, restCommandWords) => { let index = 0; index += argument.length + 1; // +1 是为了去掉 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; };
Fungsi ini menerima parameter yang diiktiraf dan selebihnya perintah, dibahagikan kepada perkataan.
(Di sini anda mula melihat "kaunter indeks". Oleh kerana kita juga perlu mencari kedudukan setiap penemuan, kita perlu menjejaki kedudukan semasa dalam teks asal).
Dalam beberapa baris terakhir fungsi, anda dapat melihat bahawa saya mengendalikan --option=something
和 --option something
kedua-dua kes.
Penghurai utama kini membahagikan teks mentah kepada baris dan kemudian kepada perkataan.
Setiap operasi mesti mengemas kini indeks global untuk menjejaki kedudukan kita dalam teks, dan indeks ini membantu kita mencari dan mencari dalam teks tanpa terperangkap dalam subrentetan yang salah, menggunakan 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 是为了换行符 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; };