0

我有一个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)不足以独自解决这个问题。因此,我请你帮我做这件事。谢谢你。

4

2 回答 2

1

根据我对您问题的理解,您需要指定命令的地址范围sed

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

/../但是,当模式不是多行时,这又会中断。这意味着您需要将它们全部设为多行。为了确保/每行只有一个,请执行以下操作:

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

这也给人一种想法,如果您首先将所有行连接到一个,您可以将多行引号视为单行:

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

PS 另外我想指出,您一开始的“技巧”有点缺陷:

 /\/.*\//

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

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

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

sed 's_/_\n/\n_g'

这样每个/人都有自己的路线。如果你看到一行只包含一个/字符,你就知道你应该把它贴在前一个字符和下一个字符上。因此,首先您对文件执行上述sed命令,然后将地址范围替换为/\//,/\//,最后您需要将这些行重新组合在一起。这可以通过

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

所以我建议你最后管这个。我不会很高兴自己必须使用它,但你总是可以将它隐藏在 shell 函数或类似的东西中。

于 2012-06-12T21:26:05.633 回答
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 先生!

PS:我也将代码放在这里(GitHub),您可以在其中跟踪一些可能的未来变化。

PS 2:^A保存此答案时字符丢失。现在它们在这里被替换为它们的 ASCII 表示。您必须将它们替换为它们的二进制表示(在插入模式下vi(1)按下^V ^A)或使用GitHub 版本

PS 3:我仍然觉得^A“hack”很丑。如果有人知道在这种情况下避免它,同时仍然像现在一样简单的中间转换代码,请分享您的想法。

于 2012-06-14T23:39:17.373 回答