我有如下输入:
Austin, Ashley D
Bender, Isaiah J
这里我尝试将名字剪切到“,”然后添加第二个名字的首字母。
例如,上面两个将是 Austina 和 Benderi。有人能帮忙吗?
答案1
您表示有兴趣通过 解决此问题cut
。应该有办法通过管道以及一些组合cut
,tr
, 有可能)paste
。但特别是当你要修改首字母的大小写时(例如,Ashley 中的前导“A”变为“Austina”中的尾随“a”),使用比 更通用的符号会更容易cut
。我建议Perl 单行代码,可能是这样或类似的,主要取决于您想要在名称中允许哪些字符:
perl -wpe 's/^(\w+),\s*(\w).*/$1\L$2/' file
这将运行 Perl 解释器,启用警告(-w
),逐行读取输入,在每一行上执行脚本并打印结果(-p
),并从下一个命令行参数中获取其脚本(-e
)。脚本本身,s/^(\w+),\s*(\w).*/$1\L$2/
我引用和单引号所以 shell 不会执行自己的扩展它由一个表达式组成,该表达式将其输入与s/pattern/replacement/
图案并将匹配替换为替代品。
在里面正则表达式,^(\w+),\s*(\w).*
:
^
匹配一行的开头。(\w+)
匹配一个或多个 (+
) 单词字符 (\w
,见下文),并捕获它们((
)
) 放入第一个捕获组。,
与本身从字面上理解相匹配。\s*
匹配零个或多个 (*
) 空格字符 (\s
)。(\w)
匹配一个单词字符 (\w
,见下文),并捕获它((
)
) 进入第二个捕获组。.*
匹配零个或多个 (*
) 可能出现在一行上的任何字符 (.
)。换句话说,它与该行的其余部分匹配。
然后$1\L$2
导致所有匹配的文本(整行,假设它做过匹配)将被替换为:
$1
,第一个捕获组的内容,不做任何修改。这是用于包含人员姓氏的字段。\L$2
,第二个捕获组 ( ) 的内容$2
,转换为小写 (\L
)。这是第一个用于包含人名(但为小写)的字符。
这可能对你来说很好。但是:
- 您可能需要修改
\w
模式中的两个出现,具体取决于您希望在名称中匹配哪些字符。\w
仅匹配字母、数字和下划线 (_
)。许多名称除了此之外还有其他字符,例如破折号和撇号。 - 还有一个问题,即什么才算是字母(这也适用于更简单的工具,尽管有时解决方案不同)。参见在正则表达式中仅匹配字母的最佳方法是什么?这与包含重音字母、附加在字母上的变音符号以及非拉丁字母的字母的名称相关。
- 大小写转换是一个比表面上更难的问题。不同的书面语言不仅有不同的字母,而且对于某些相同的字母,它们的大小写转换也不同。
另一个非常简单的我能想到的选择\w
——允许名称包含任何内容其他可以通过将每个空格或-- 替换为来,
实现。\w
[^,\S]
[
]
字符类,领先的^
意味着该类包含所有但指定的字符(即不是与字符类之外的含义相关),,
从字面上指定自身,并且\s
指定所有空白字符。
perl -wpe 's/^([^,\s]+),\s*([^,\s]).*/$1\L$2/' file
有关 Perl 中正则表达式的更多信息,请参阅perldoc perlretut
和perldoc perlre
。你提出的问题是只是复杂到足以激励我使用比基本文本处理工具更复杂(因而更复杂)的工具。由于您可能能够找到使用这些工具的方法,因此如果您这样做,我当然不会责怪您!但我认为这可能对未来甚至更复杂的问题仍然有帮助。
答案2
使用 cut、管道、tr、paste(和 sed)的建议解决方案可能是:
cut -f1 -d, foo >bar; cut -f2 -d" " foo | cut -c1 |tr "A-Z" "a-z" >bar2 ;paste bar bar2|sed -e "s/\x9//g"
其中 foo 是您输入的文件。因此,您可以使用 cut 和其他方法管理任务,但 pearl 解决方案更优雅、更合适。