伪代码是以下内容的延续这个答案
gsed 's/|/1)/g' 's/|/2)/2g' 's/|/3)/3g' 's/|/5)/4g' 's/|/5)/5g'
<input.csv >output.csv
这当然是行不通的。我感兴趣的是如何gsed
管理这样的循环。
如何gsed
扩展到这样的循环?
答案1
对于上面的情况,你可以这样做:
gsed 's/|/1)/; s/|/2)/; s/|/3)/; s/|/4)/; s/|/5)/'
例子:
$ echo '| | | | |' | sed 's/|/1)/; s/|/2)/; s/|/3)/; s/|/4)/; s/|/5)/'
1) 2) 3) 4) 5)
如果您可以提前估计|
一行中的最大数量并s/|/N)/
相应地添加,则此方法有效。
如果您无法估计|
一行上的最大数量,仍然可以使用 来完成gsed
,使用保持缓冲区中的计数器,并使用这个聪明的装置作者:布鲁诺·海布尔。但实际的实现有点棘手,因此我将其留给受虐狂精明的读者。
当然,最简单的方法是使用awk
:
awk '{ cnt = 0; while(sub(/\|/, ++cnt ")")); print }'
证明:
$ echo '| | | | |' | awk '{ cnt = 0; while(sub(/\|/, ++cnt ")")); print }'
1) 2) 3) 4) 5)
答案2
另一个 sed:
sed -n '1x;1s/^/12345/;1x;G;:t
s/|\(.*\n)\(.\)/\2)\1/;tt
P' <infile >outfile
但可能awk
更适合这里。
一个更为复杂的解决方案:
鉴于您的其他问题的输出......
Question ipsun; option 1 | option 2 | option 3 | option 4 | ... | option n
Que|stion ipsun; option 1 | option 2 | option 3 | option 4 | ... | option n
...并将其传递给...
sed ' s/^/!/;/|/s/\(.*;\)*[^|]*/&\
|/g; s/.*\(\n\).*/::::::\1&\1::/' |
nl -d:: -hp^\) -s\)\ |
sed -e' /./{ s/^ *!//;P;d;:n' -e'};N;/\n$/!bn
s/[0-9 ]*\n *\([^;|)]*) |*\)|/ (\1/g;D'
...要得到...
Question ipsun; option (1) | option (2) | option (3) | option (4) | ... (5) | option n (6)
Que|stion ipsun; option (1) | option (2) | option (3) | option (4) | ... (5) | option n (6)
我想我会打破它...
sed ' s/^/!/;/|/s/\(.*;\)*[^|]*/&\
)/g; s/.*\(\n\).*/::::::\1&\1::/' |..
。
……是第一阶段。这为 准备输出nl
。
nl
在标准实用程序中具有独特的功能 -(其中大多数将整个输入流视为单个内聚单元)- 因为它可以逻辑上通过分隔输入文件部分。nl
将输入分为标头,身体, 和页脚对于每个逻辑页它的。对于每页的三个部分,用户可以指定不同的数字风格对于每个,并且对于每个逻辑页用户可以收到新线路数数。
有了sed
上面我做的:
s/^/!/
- 如果不出意外,这可以确保s 的节定界符不会意外出现在输入中,但这也将用作在处理的另一侧
nl
修剪 的前导空白的标记。nl
- 如果不出意外,这可以确保s 的节定界符不会意外出现在输入中,但这也将用作在处理的另一侧
/|/s...
- 这只尝试将替换应用于明确匹配至少一个管道的行
|
。
- 这只尝试将替换应用于明确匹配至少一个管道的行
...s/\(.*;\)*[^|]*/&\n|/g
- 这对可以匹配任何内容的模式应用全局替换(甚至什么也没有)而是一个
|
管道,后面有时没有;
分号。- 因为
\(.*;\)*
被匹配*
零次或多次,所以大多数时候它匹配空字符串。但是,匹配器第一次在包含至少一个分号的行上应用子表达式时;
,会有效地跳过从行首到最后一个分号的整个模式空间范围。 - 这样做的目的是避免匹配
[^|]*
出现的任何子字符串前分隔分号,从而跳过问题整个字符串的一部分。
- 因为
- 对于此模式的每次出现,它都会被替换为
&
自身,并附加一个附加的\n|
。
- 这对可以匹配任何内容的模式应用全局替换(甚至什么也没有)而是一个
s/.*\(\n\).*/::::::\1&\1::/
- 这会将至少包含一个
\n
ewline 的任何模式空间替换为六个冒号,然后是我们捕获的\1\n
ewline,然后是&
它本身,然后是我们捕获的\1\n
ewline,然后是两个冒号。 - 我将使用字符串
::
作为nl
的节-d
分隔符。这些字符串之一开始nl
页脚部分,其中三个字符串标记一个标头- 和一个新的逻辑页面。 nl
将要仅有的如果分隔符单独出现在一行上,则可以识别该分隔符。
- 这会将至少包含一个
...此时数据流看起来像...
::::: !问ipsun;选项1 ||选项2 ||选项3 ||选项4 || ... ||选项n | :: ::::: !问题|stion ipsun;选项1 ||选项2 ||选项3 ||选项4 || ... ||选项n | ::
...现在我们可以通过...
...|nl -d:: -hp^\) -s\)\ |...
-d::
- 这指定了
::
分隔符字符串。 nl
将在输出中用空行替换-d
输入中的每个分隔符字符串。nl
将在其输出行的开头插入数字,或者在未编号的行的开头插入空格以匹配其数字字符串的长度。- 因此,其输出中唯一空白的行是那些曾经是其分隔符字符串的行。
- 这指定了
-hp^\|
- 这是一个
-h
领导者风格意义对与正则表达式模式匹配的所有行进行编号。 nl
将在一个标头发生在仅包含的行之间的每个行序列的状态::::::
另一个只包含::
。- 默认
nl
号码仅有的身体各部分并没有编号标头或者页脚根本不。
- 这是一个
-s\)\
- 这是一个分隔符字符串,它将
nl
插入到它编号的每行的行头和它之前插入的数字之间。
- 这是一个分隔符字符串,它将
...此时数据流看起来像...
!问ipsun;选项1 1) ||选项2 2) ||选项3 3)||选项4 4) || ... 5)||选项n 6)| !问题|stion ipsun;选项1 1) ||选项2 2) ||选项3 3)||选项4 4) || ... 5)||选项n 6)|
...最后我们可以用...来处理这个问题
sed -e' /./{s/^ *!//;P;d;:n' -e '};N;/\n$/!bn
s/[0-9 ]*\n *\([^;|)]*) |*\)|/ (\1/g;D'
/./{...
- 在任何包含至少一个字符的行上,这都会开始一个以匹配为中心的函数。
- 后面可能有几个命令,但仅适用于首先与函数父地址匹配的模式空间。
...{s/^ *!//
nl
在这里,我们从匹配行的头部修剪所有插入的空格和插入的刘海。
P;d;:n
- 这
P
会打印到\n
模式空间中的第一个 ewline。 - 然后
d
删除模式空间。 - 然后定义分支标签
:n
。 - 从现在开始,我们只处理以空白行开头的一系列行。
- 这
N
- 这会拉入
N
ext 输入行并将其附加到\n
ewline 字符后面的模式空间。
- 这会拉入
/\n$/!bn
- 虽然模式空间不
$
以 ewline 结尾(如果ext 行为空,\n
则会如此) ,但我们始终回到标签 - 堆叠输入。N
b
:n
- 虽然模式空间不
s/[0-9 ]*\n *\([^;|)]*) |*\)|/ (\1/g'
- 这是
g
局部替换。 - 它取代了每个序列...
*
零个或多个[0-9 ]
字符- 接下来是
\n
ewline - 随后是
*
零个或多个<空格> - 后跟
*
零个或多个^
非冒号或管道字符 - 后面跟着一个右
)
括号 - 可能后面跟着一个
|
管道 - 肯定后面跟着一个
|
管道 - 仅包含
^
非冒号/管道字符、右括号和可能的管道。
- 这是
D
- 现在我们
D
删除\n
模式空间中的第一个行(这是第一个字符,因为该序列以空行开始)并将其余部分发送回脚本顶部,以P
在下一个新周期中修剪和打印空格和爆炸。
- 现在我们
最终结果是:
Question ipsun; option (1) | option (2) | option (3) | option (4) | ... (5) | option n (6)
Que|stion ipsun; option (1) | option (2) | option (3) | option (4) | ... (5) | option n (6)