特定于sed - 在双引号多行字符串中执行许多替换

时间:2012-06-12 20:10:18

标签: sed

我有一个sed(1)脚本执行给定的许多逐步转换(替换) 输入流,适用于任务本身。现在,我需要的是限制这些 操作/内部“/”仅引用多行字符串。输入流是简单文本 包含多行“/”引用字符串的文件我需要执行我的 s///命令的序列。我知道在sed(1)中实现这一点很难 我仍然希望有人知道如何。我到目前为止的脚本(但在单行基础上正常工作)如下。

sed(1)“诡计”在开头和时候 脚本的结尾,其余的只是s/// s表达式的序列,它是正确的:

#! /bin/sed -f

# Convert /PinYin/ strings to /UTF-8 PinYin/ strings.
# Notice: /PinYin/ strings MUST NOT be multiline (to do).

/\/.*\// {

    s/\//\
/g

:a 
    h
    s/[^\n]*\n//
    s/\n.*//

    s/ang1/||aq||ng/g
    s/ang2/||aw||ng/g
    s/ang3/||ae||ng/g
    s/ang4/||ar||ng/g

    s/eng1/||eq||ng/g
    s/eng2/||ew||ng/g
    s/eng3/||ee||ng/g
    s/eng4/||er||ng/g

    s/ing1/||iq||ng/g
    s/ing2/||iw||ng/g
    s/ing3/||ie||ng/g
    s/ing4/||ir||ng/g

    s/ong1/||oq||ng/g
    s/ong2/||ow||ng/g
    s/ong3/||oe||ng/g
    s/ong4/||or||ng/g

    s/an1/||aq||n/g
    s/an2/||aw||n/g
    s/an3/||ae||n/g
    s/an4/||ar||n/g

    s/en1/||eq||n/g
    s/en2/||ew||n/g
    s/en3/||ee||n/g
    s/en4/||er||n/g

    s/in1/||iq||n/g
    s/in2/||iw||n/g
    s/in3/||ie||n/g
    s/in4/||ir||n/g

    s/un1/||uq||n/g
    s/un2/||uw||n/g
    s/un3/||ue||n/g
    s/un4/||ur||n/g

    s/ao1/||aq||o/g
    s/ao2/||aw||o/g
    s/ao3/||ae||o/g
    s/ao4/||ar||o/g

    s/ou1/||oq||u/g
    s/ou2/||ow||u/g
    s/ou3/||oe||u/g
    s/ou4/||or||u/g

    s/ai1/||aq||i/g
    s/ai2/||aw||i/g
    s/ai3/||ae||i/g
    s/ai4/||ar||i/g

    s/ei1/||eq||i/g
    s/ei2/||ew||i/g
    s/ei3/||ee||i/g
    s/ei4/||er||i/g

    s/a1/||aq||/g
    s/a2/||aw||/g
    s/a3/||ae||/g
    s/a4/||ar||/g

    s/a1/||aq||/g
    s/a2/||aw||/g
    s/a3/||ae||/g
    s/a4/||ar||/g

    s/er2/||ew||r/g
    s/er3/||ee||r/g
    s/er4/||er||r/g

    s/lyue/l||u:||e/g
    s/nyue/n||u:||e/g

    s/e1/||eq||/g
    s/e2/||ew||/g
    s/e3/||ee||/g
    s/e4/||er||/g

    s/o1/||oq||/g
    s/o2/||ow||/g
    s/o3/||oe||/g
    s/o4/||or||/g

    s/i1/||iq||/g
    s/i2/||iw||/g
    s/i3/||ie||/g
    s/i4/||ir||/g

    s/nyu3/n||u:e||/g

    s/lyu/l||u:||/g

    s/u:1/||u:q||/g
    s/u:2/||u:w||/g
    s/u:3/||u:e||/g
    s/u:4/||u:r||/g
    s/u:0/||u:s||/g

    s/u1/||uq||/g
    s/u2/||uw||/g
    s/u3/||ue||/g
    s/u4/||ur||/g

    s/||aq||/ā/g
    s/||aw||/á/g
    s/||ae||/ǎ/g
    s/||ar||/à/g

    s/||eq||/ē/g
    s/||ew||/é/g
    s/||ee||/ě/g
    s/||er||/è/g

    s/||iq||/ī/g
    s/||iw||/í/g
    s/||ie||/ǐ/g
    s/||ir||/ì/g

    s/||oq||/ō/g
    s/||ow||/ó/g
    s/||oe||/ǒ/g
    s/||or||/ò/g

    s/||uq||/ū/g
    s/||uw||/ú/g
    s/||ue||/ǔ/g
    s/||ur||/ù/g

    s/||u:q||/ǖ/g
    s/||u:w||/ǘ/g
    s/||u:e||/ǚ/g
    s/||u:r||/ǜ/g
    s/||u:s||/ü/g

    G
    s/\([^\n]*\)\n\([^\n]*\)\n[^\n]*\n/\2\/\1\//
    /\n/ b a
}

示例输入:

Some text containing for instance Chinese greeting /ni3
hao3/ and perhaps some other Chinese sentence, say /ni2
kan4, .../

预期产出:

Some text containing for instance Chinese greeting /nǐ
hǎo/ and perhaps some other Chinese sentence, say /ní
kàn, .../

我对sed(1)的了解并不像我自己解决这个问题那么强大。因此,我请你帮助我。谢谢。

2 个答案:

答案 0 :(得分:1)

根据我在您的问题中的理解,您需要为sed命令指定address range

sed '/\//,/\// {command1; command2; ...}'

然而,当/../模式多行时,这将会中断。这意味着您需要使多行全部。要确保每行只有一个/

sed 's_/_\n/_g' | sed {main sed command}

这也让人觉得如果你把所有行加到一行,你可以将多行引号视为一行:

cat myfile | tr '\n' ' ' | sed {your current commands}

P.S。另外我想指出一下你的“诀窍”有点瑕疵:

 /\/.*\//

这是贪婪的,所以它不会正确处理同一行上的多个模式。因此,第二种方法可能无法正常工作。

编辑:好吧,这比我想象的更复杂(或者我太累了,看不到更简单的方法)。

要将线条重新组合在一起,您需要以“独特”方式拆分它们,以便稍后您可以分辨出脚本引入了哪些换行符。我建议这样做

sed 's_/_\n/\n_g'

以便每个/获得自己的行。如果您看到一行由唯一的/字符组成,您知道应该将其粘贴到上一个字符和下一个字符。首先,对文件执行上述sed命令,然后使用地址范围/\//,/\//进行替换,最后需要将这些行重新组合在一起。这可以通过

完成
sed ':a $!{N;ba};s/\n\/\n/\//g'

所以我建议你最终解决这个问题。我不会为自己使用它而感到高兴,但你总是可以将它隐藏在shell函数或类似的东西中。

答案 1 :(得分:0)

最后,只需对原始sed(1)代码进行少量改进即可轻松实现。也许它可以以某种方式更好地完成,但是当转换代码在“行范围”中工作时,我设法让它成为(对这个问题的本质并不重要的微小改进)而是在模式空间中读取整个文件,替换使用\001^A)字符的换行符,让原始代码执行此操作,最后将^A字符替换回换行符。这是:

#! /bin/sed -f

#  pinyin2utf8.sed -- Convert US-ASCII Pinyin to UTF-8
#  Copyright (C) 2012 Matous J. Fialka, <http://mjf.cz/>
#  Released under the terms of The MIT License
#
#  DESCRIPTION
#   Script converts all occurences of US-ASCII encoded Pinyin text
#   enclosed by the solidus characters pairs to UTF-8 encoded text.
#
#  USAGE
#   pinyin2utf8.sed filename [ > filename.out ]
#
#  WARNINGS
#   Script contains the ^A control character, usually displayed as
#   mentioned in most text editors, that can be usually reproduced
#   by pressing ^V ^A key sequence. The ^A control characters thus
#   MUST NOT occure in the input stream.  To find the sequences in
#   the script lookup the y/// command in the code, please.
#
#   In the US-ASCII encoded Pinyin to UTF-8 Pinyin conversion code
#   special delimiting sequences of left and right parentheses are
#   used and those two delimiting sequences of left or righ parens
#   SHOULD NOT be used in the input stream.

: 0

$! {
    N
    b 0
}

# HERE BE DRAGONS

y/\n/^A/

y/\//\
/

: a

h

s/[^\n]*\n//
s/\n.*//

# CONVERSION CODE BEGINNING

s/ang1/(((aq)))ng/g
s/ang2/(((aw)))ng/g
s/ang3/(((ae)))ng/g
s/ang4/(((ar)))ng/g
s/eng1/(((eq)))ng/g
s/eng2/(((ew)))ng/g
s/eng3/(((ee)))ng/g
s/eng4/(((er)))ng/g
s/ing1/(((iq)))ng/g
s/ing2/(((iw)))ng/g
s/ing3/(((ie)))ng/g
s/ing4/(((ir)))ng/g
s/ong1/(((oq)))ng/g
s/ong2/(((ow)))ng/g
s/ong3/(((oe)))ng/g
s/ong4/(((or)))ng/g

s/an1/(((aq)))n/g
s/an2/(((aw)))n/g
s/an3/(((ae)))n/g
s/an4/(((ar)))n/g
s/en1/(((eq)))n/g
s/en2/(((ew)))n/g
s/en3/(((ee)))n/g
s/en4/(((er)))n/g
s/in1/(((iq)))n/g
s/in2/(((iw)))n/g
s/in3/(((ie)))n/g
s/in4/(((ir)))n/g
s/un1/(((uq)))n/g
s/un2/(((uw)))n/g
s/un3/(((ue)))n/g
s/un4/(((ur)))n/g
s/ao1/(((aq)))o/g
s/ao2/(((aw)))o/g
s/ao3/(((ae)))o/g
s/ao4/(((ar)))o/g
s/ou1/(((oq)))u/g
s/ou2/(((ow)))u/g
s/ou3/(((oe)))u/g
s/ou4/(((or)))u/g
s/ai1/(((aq)))i/g
s/ai2/(((aw)))i/g
s/ai3/(((ae)))i/g
s/ai4/(((ar)))i/g
s/ei1/(((eq)))i/g
s/ei2/(((ew)))i/g
s/ei3/(((ee)))i/g
s/ei4/(((er)))i/g

s/a1/(((aq)))/g
s/a2/(((aw)))/g
s/a3/(((ae)))/g
s/a4/(((ar)))/g
s/a1/(((aq)))/g
s/a2/(((aw)))/g
s/a3/(((ae)))/g
s/a4/(((ar)))/g

s/er2/(((ew)))r/g
s/er3/(((ee)))r/g
s/er4/(((er)))r/g

s/lyue/l(((u:)))e/g
s/nyue/n(((u:)))e/g

s/e1/(((eq)))/g
s/e2/(((ew)))/g
s/e3/(((ee)))/g
s/e4/(((er)))/g
s/o1/(((oq)))/g
s/o2/(((ow)))/g
s/o3/(((oe)))/g
s/o4/(((or)))/g
s/i1/(((iq)))/g
s/i2/(((iw)))/g
s/i3/(((ie)))/g
s/i4/(((ir)))/g

s/nyu3/n(((u:e)))/g

s/lyu/l(((u:)))/g

s/u:1/(((u:q)))/g
s/u:2/(((u:w)))/g
s/u:3/(((u:e)))/g
s/u:4/(((u:r)))/g
s/u:0/(((u:s)))/g

s/u1/(((uq)))/g
s/u2/(((uw)))/g
s/u3/(((ue)))/g
s/u4/(((ur)))/g

s/(((aq)))/ā/g
s/(((aw)))/á/g
s/(((ae)))/ǎ/g
s/(((ar)))/à/g
s/(((eq)))/ē/g
s/(((ew)))/é/g
s/(((ee)))/ě/g
s/(((er)))/è/g
s/(((iq)))/ī/g
s/(((iw)))/í/g
s/(((ie)))/ǐ/g
s/(((ir)))/ì/g
s/(((oq)))/ō/g
s/(((ow)))/ó/g
s/(((oe)))/ǒ/g
s/(((or)))/ò/g
s/(((uq)))/ū/g
s/(((uw)))/ú/g
s/(((ue)))/ǔ/g
s/(((ur)))/ù/g

s/(((u:q)))/ǖ/g
s/(((u:w)))/ǘ/g
s/(((u:e)))/ǚ/g
s/(((u:r)))/ǜ/g
s/(((u:s)))/ü/g

# CONVERSION CODE END

G

s/\([^\n]*\)\n\([^\n]*\)\n[^\n]*\n/\2\/\1\//

/\n/ b a

# HERE BE DRAGONS

y/^A/\
/

示例输入文字:

$ cat test.in
ni3 hao3
/ni3 hao3/
ni3 hao3 /ni3 hao3/
/ni3 hao3/ ni3 hao3
ni3 hao3 /ni3 hao3/ ni3 hao3
ni3 hao3 /ni3 hao3/ ni3 hao3 /ni3 hao3/
/ni3 hao3/ ni3 hao3 /ni3 hao3/
/ni3 hao3/ ni3 hao3 /ni3 hao3/ ni3 hao3
ni3 hao3 /ni3 hao3/ ni3 hao3 /ni3 hao3/ ni3 hao3
/ni3 hao3/ ni3 hao3 /ni3 hao3/ ni3 hao3 /ni3 hao3/

ni3 hao3 /ni3
hao3/ ni3 hao3

/ni3 hao3
ni3
hao3
ni3 hao3/ ni3 hao3

示例运行:

$ pinyin2utf8.sed test.in
ni3 hao3
/nǐ hǎo/
ni3 hao3 /nǐ hǎo/
/nǐ hǎo/ ni3 hao3
ni3 hao3 /nǐ hǎo/ ni3 hao3
ni3 hao3 /nǐ hǎo/ ni3 hao3 /nǐ hǎo/
/nǐ hǎo/ ni3 hao3 /nǐ hǎo/
/nǐ hǎo/ ni3 hao3 /nǐ hǎo/ ni3 hao3
ni3 hao3 /nǐ hǎo/ ni3 hao3 /nǐ hǎo/ ni3 hao3
/nǐ hǎo/ ni3 hao3 /nǐ hǎo/ ni3 hao3 /nǐ hǎo/

ni3 hao3 /nǐ
hǎo/ ni3 hao3

/nǐ hǎo
nǐ
hǎo
nǐ hǎo/ ni3 hao3

它似乎工作得很好(至少满足我的需求),因此我认为这个问题是关闭的。非常感谢所有参与的人,特别是Lev Levitsky先生!

P.S。:我还将代码here (GitHub)放在了可以跟踪未来可能发生的变化的地方。

P.S。 2:保存此答案时^A个字符丢失了。现在,它们将在此处替换为ASCII表示。您必须将它们替换为二进制表示形式(在vi(1)按插入模式下的^V ^A)或使用GitHub version代替。

P.S。 3:我仍觉得^A“黑客”非常难看。如果有人知道在这种情况下避免使用中间转换代码,尽管现在很简单,请分享您的想法。