需要用文件中的行号和位置号替换单词

需要用文件中的行号和位置号替换单词

我需要用文件中的行号和位置号替换单词:

文件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),因为它们不应该被视为分隔符。perlPCRE(带有(*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++

然后该列表的每个元素都用空格连接并打印。

输出将转到标准输出。如果您希望更改输入文件,请-iperl和 之间添加选项-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 中的 ,使用NRI 获取当前行号,并i用于获取当前列索引。

相关内容