我需要用文件中的行号和位置号替换单词:
文件1有:
ABC XYZ UIO WER GFH
DFG JHKS
WEQ RWT DSW
ANSN WERER WERT QAZX UWRE AA
需要替换其内容如下:
S_11 S_12 S_13 S_14 S_15
S_21 S_22
S_31 S_32 S_33
S_41 S_42 S_43 S_44 S_45 S_46
话就不再重复了。每个文件可能有不同的单词集和数量。
答案1
另一种perl
基于 - 的方法:
perl -pe 'my $i; s{\S+}{"S_$." . ++$i}ge'
这会将每行中的每个非 ASCII 空白字符序列替换为S_<line-number><word-number>
,保留现有的空白。
如果输入可能包含非 ASCII 空白字符,例如:
U+0085 下一行
U+00A0 不间断空格
U+1680 OGHAM 空格标记
U+2000 EN QUAD
U+2001 EM QUAD
U+2002 EN 空格
U+2003 EM 空格
U+2004 每三个空格
U+2005四格空格
U+2006 六格空格
U+2007 数字空格
U+2008 标点符号空格
U+2009 细空格
U+200A 头发空格
U+2028 行分隔符
U+2029 段落分隔符
U+202F 窄否-打破空间
U+205F 中等数学空间
U+3000 表意空间
它们根据用户的区域设置进行编码,您可以添加该-Mopen=locale
选项。
您可能想也可能不想排除“不间断”空格(上面的 U+00A0、U+2007 和 U+202F),因为它们不应该被视为分隔符。perl
PCRE(带有(*UCP)
)包括它们,GNU 语言环境[:space:]
CTYPE
类别不包括它们。在我的系统上,我发现 U+0085 不包含在语言环境中[:space:]
,PCRE 还包含 U+180E 蒙古元音分隔符(其中过去在 Unicode 中被归类为空白,但现在不再是)。perl
另见\PZ
字符不是(大写p
)分类为分隔符和\P{Zs}
字符不是归类为空格分隔符(包括 TAB 在内的控制字符不被视为分隔符)。我发现这\p{Zs}
是它本身的子集,\pZ
是 的子集\s
。
答案2
$ perl -lane '$i=1; print join(" ", map { "S_$." . $i++ } @F)' file1
S_11 S_12 S_13 S_14 S_15
S_21 S_22
S_31 S_32 S_33
S_41 S_42 S_43 S_44 S_45 S_46
-l
自动处理行尾-a
自动将输入行拆分为名为 @F 的数组-n
循环输入的每一行而不打印任何内容,类似于sed -n
.-e
下一个参数是要执行的脚本。
每行都会自动拆分(在空白处)到数组中@F
(类似于如何awk
将每个输入行自动拆分为 $1、$2、...、$NF)。
该脚本$i
在每个输入行的开头重置为 1。
该函数返回一个由文字字符串、行号 ( ) 和变量(每次使用时递增 $i)map
组成的字符串列表,该列表对于 @F 中的每个元素都有一个元素。S_
$.
$i
++
然后该列表的每个元素都用空格连接并打印。
输出将转到标准输出。如果您希望更改输入文件,请-i
在perl
和 之间添加选项-l
。或者,-i.bak
如果您还希望在覆盖原始文件之前对其进行备份。
顺便说一句,因为输出中的行号 ($.) 和字计数器 ($i) 之间没有分隔符,所以无法区分第一行的第十一个字 (“S_111”) 和第十一行的第一个字(也是“S_111”)。我建议在这两个值之间添加一个分隔符(例如,.
或另一个)。_
并且,可能会对数字进行零填充,以便它们始终具有相同的位数。例如,使用sprintf()
里面的函数map
:
$ perl -lane '$i=1; print join(" ", map { sprintf "S_%03i.%03i", $., $i++ } @F)' file1
S_001.001 S_001.002 S_001.003 S_001.004 S_001.005
S_002.001 S_002.002
S_003.001 S_003.002 S_003.003
S_004.001 S_004.002 S_004.003 S_004.004 S_004.005 S_004.006
答案3
您如何知道给定的输出,例如S_1234
它是否意味着第 12 行的第 34 列或第 123 行的第 4 列或其他内容?_
对于接下来要处理此数据的任何操作来说,在输出中的行号和列号之间不使用分隔符似乎是一个坏主意。
这将执行您所要求的操作:
$ awk '{for (i=1; i<=NF; i++) $i="S_" NR i} 1' file
S_11 S_12 S_13 S_14 S_15
S_21 S_22
S_31 S_32 S_33
S_41 S_42 S_43 S_44 S_45 S_46
但请考虑一下:
$ awk '{for (i=1; i<=NF; i++) $i="S_" NR "_" i} 1' file
S_1_1 S_1_2 S_1_3 S_1_4 S_1_5
S_2_1 S_2_2
S_3_1 S_3_2 S_3_3
S_4_1 S_4_2 S_4_3 S_4_4 S_4_5 S_4_6
因此您可以通过其独立值可靠地区分输出中的行号和列号。
上面的代码将从每行中删除任何前导/尾随空格,并将所有连续的空格链转换为单个空白字符。我怀疑这是否是一个问题,但请告诉我们是否存在。
答案4
您可以使用awk
:
awk '{for (i=1; i<=NF; i++){ printf "S_"NR i " " } print "" }' file1 > newfile
mv newfile file1
或者如果您正在使用gawk
(在 Linux 中awk
通常链接到gawk
):
gawk -i inplace '{for (i=1; i<=NF; i++){ printf "S_"NR i " " } print "" }' file1
in for (i=1; i<=NF; i++)
awk 用于循环每行的总列数。NF
存储每行的当前列数。
关于printf "S_"NR i " "
awk 中的 ,使用NR
I 获取当前行号,并i
用于获取当前列索引。