使用regex或其他方法从两个字符串之间选择多行文本

uubf1zoe  于 2023-10-22  发布在  其他
关注(0)|答案(3)|浏览(104)

我试图从一个digibyte.conf文件的不同部分读取变量。下面是一个示例文件:

# Generated by https://jlopp.github.io/bitcoin-core-config-generator/

# This config should be placed in following path:
# ~/.digibyte/digibyte.conf

# [chain]
# Run this node on the DigiByte Test Network. Equivalent to -chain=test
testnet=1
# Test Network.
chain=test

# [rpc]
# Accept command line and JSON-RPC commands.
server=1
# Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times. (default: 127.0.0.1 and ::1 i.e., localhost)
rpcbind=127.0.0.1

# [wallet]
# Do not load the wallet and disable wallet RPC calls.
disablewallet=1

# [Sections]
# Most options automatically apply to mainnet, testnet, and regtest networks.
# If you want to confine an option to just one network, you should add it in the relevant section.
# EXCEPTIONS: The options addnode, connect, port, bind, rpcport, rpcbind and wallet
# only apply to mainnet unless they appear in the appropriate section below.

# Options only for mainnet
[main]

# Listen for incoming connections on non-default mainnet port. Mainnet default is 12024.
# Setting the port number here will override the default testnet port numbers.
port=12024

# Bind to given address to listen for JSON-RPC connections. This option is ignored unless
# -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation
# for IPv6. This option can be specified multiple times. (default: 127.0.0.1 and ::1 i.e., localhost)
rpcbind=127.0.0.1

# Listen for JSON-RPC connections on this port. Mainnet default is 14022. 
rpcport=14022

# Options only for testnet
[test]

# Listen for incoming connections on non-default testnet port. Testnet default is 12026.
# Setting the port number here will override the default testnet port numbers.
port=12026

# Bind to given address to listen for JSON-RPC connections. This option is ignored unless
# -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation
# for IPv6. This option can be specified multiple times. (default: 127.0.0.1 and ::1 i.e., localhost)
rpcbind=127.0.0.1

# Listen for JSON-RPC connections on this port. Testnet default is 14023.
rpcport=14023

# Options only for regtest
[regtest]

# regtest variables go here

我希望能够从文件中获取特定的部分,这样我就可以检查它是否包含某些变量。举例来说:

  • 选择从文件开头到第一行以'['字符开头的所有内容。这将选择[Sections]上方的所有内容。
  • 选择测试网部分。也就是说,选择从[test]开始的一行和它下面以'['字符开始的下一行之间的所有内容。(有些用户可能有不同顺序的部分,所以它不能假设下一个部分将是[regtest]。这将始终选择专门为testnet指定的所有内容。
  • 选择regtest部分。也就是说,选择[regtest]开始的行和文件结尾之间的所有内容。有时候,正在搜索的部分可能是文件中的最后一部分,因此没有结束字符“["。我需要同时搜索这两种情况。

这是帮助设置和监视DigiByte节点的更大脚本的一部分。
到目前为止,我已经成功地使用awk和正则表达式对测试网部分进行了基本搜索:awk '/^\[test\]/,/^\[regtest\]/' ~/.digibyte/digibyte.conf
这基本上是按预期工作的。
但是,如果我将其更改为只搜索下一行以'['开始而不是'[regtest]'结束,我什么也得不到:awk '/^\[test\]/,/^\[/' ~/.digibyte/digibyte.conf
我也不知道如何选择从文件的开头到字符串,或者从字符串到文件的结尾。
理想情况下,这应该在ubuntu/debian服务器上工作,而不需要安装额外的软件包。
任何帮助将不胜感激。

t0ybt7op

t0ybt7op1#

我认为问题很简单,^\[将匹配行“[test]”本身!
因此,一种选择是使用负向前看来表示“后面不跟单词 test”,但它们在awk中不可用。因为你不知道下一节是什么,所以有点复杂。
可以这样做:

awk '/^\[test\]/,/^\[[^t]/' ~/.digibyte/digibyte.conf

但问题是,如果下一个部分被命名为“[throttle]”,那么它将不匹配,因为它也以字母“t”开头。
我试着用/\r?\n\[/找到下一个部分,但似乎不起作用。也许你应该使用另一个工具,比如 ripgrepperl。两者都可以处理多行搜索。

Good old grep to the rescue

  • ripgrep* 不会被安装。但 grep 应该。在Linux版本中,grep 具有PCRE引擎,并带有-P选项。也可以使用(?s)在模式中启用s(dot match all)标志,并使用-o选项仅打印匹配项。另一个技巧是启用 grep-z选项,以便数据行以0字节而不是换行符结束。这样,就可以读取多行,而不是像 grep 通常那样一行一行地读取。

甚至可以使用查找表来避免与下一节的开头相匹配。
所以我们可以这样做:

grep \
  -Pzo \
  '(?s)(?<=\n|^)\[test\].*?(?=\r?\n\[)' \
  ~/.digibyte/digibyte.conf
jdg4fx2g

jdg4fx2g2#

您还可以使用Python中的正则表达式从digibyte.conf中提取所需的部分!

import re

#reading the digibyte.conf
with open('digibyte.conf', 'r') as file:
    content = file.read()

#select everything from the beginning of the file till the first line that starts with a '[' character
section1 = re.search(r'^.*?(?=\n\[)', content, re.MULTILINE | re.DOTALL).group(0)

#select the testnet section
section2 = re.search(r'\[test\](.*?)^(?=\[)', content, re.MULTILINE | re.DOTALL).group(1)

#select the regtest section
section3 = re.search(r'\[regtest\](.*?)\Z', content, re.MULTILINE | re.DOTALL).group(1)

print("Section 1:")
print(section1)
print("")

print("Section 2:")
print(section2)
print("")

print("Section 3:")
print(section3)

通过Perl:

#!/usr/bin/perl

use strict;
use warnings;

#read the digibyte.conf
open(my $fh, '<', 'digibyte.conf') or die "Failed to open file: $!";
my $content = do { local $/; <$fh> };

#selecting everything from the beginning of the file till the first line that starts with a '[' character
my ($section1) = $content =~ /^(.*?)(?=\[)/s;

#select the testnet section
my ($section2) = $content =~ /\[test\](.*?)(?=\[)/s;

#select the regtest section
my ($section3) = $content =~ /\[regtest\](.*)/s;

print "Section 1:\n";
print "$section1\n\n";

print "Section 2:\n";
print "$section2\n\n";

print "Section 3:\n";
print "$section3\n";
zte4gxcn

zte4gxcn3#

你可以使用混合的符号来实现这一点,

\s: to match non-printable chars, like newline.
\S: to match any printable
\n{1}: to get the line above too

但是在正则表达式中加入一些逻辑会更复杂,比如一个或运算符,比如如果下一行有一些字符很难,尝试使用:

[this|this2] : to match 'this' or 'this2'

相关问题