![请提供 awk、sed 或其他文本处理建议](https://linux22.com/image/1578216/%E8%AF%B7%E6%8F%90%E4%BE%9B%20awk%E3%80%81sed%20%E6%88%96%E5%85%B6%E4%BB%96%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86%E5%BB%BA%E8%AE%AE.png)
我有以下重复的文本模式需要重新格式化。
通常这应该很容易,即使使用标准文本编辑器,但在这种情况下,我需要扩展括号中的信息并枚举它们。
我最好举一个例子:
"Gene Code (1A - 1F) D2 fragment, D74F"
我需要能够让最终的产品看起来像这样:
Gene Code, 1A, D2 fragment, D74F
Gene Code, 1B, D2 fragment, D74F
Gene Code, 1C, D2 fragment, D74F
Gene Code, 1D, D2 fragment, D74F
Gene Code, 1E, D2 fragment, D74F
Gene Code, 1F, D2 fragment, D74F
问题在于括号内的初始字符串可以是任何数字,例如 1A-1F 或 3D-3H 等。这是唯一可移动的信息位。括号内的数字始终相同,只是字母需要用其相关数字进行扩展。
因此需要以某种方式将字母与数字关联起来。
这对我来说看起来太费脑筋了。任何帮助都非常感谢。顺便说一句,我是新手。
答案1
这个 bash 脚本
#!/bin/bash
PART1=$(echo "$1" | sed 's/\(.*\)\s(.*/\1/')
PART3=$(echo "$1" | sed 's/.*)\(.*\)/\1/')
PART2=$(echo "$1" | sed 's/.*(\s*\(.*\)).*/\1/')
START=$(echo "$PART2" | sed 's/\s*-.*//')
END=$(echo "$PART2" | sed 's/.*-\s*//')
STARTNUM=$(echo "$START" | sed 's/^\(.\).*/\1/')
ENDNUM=$(echo "$END" | sed 's/^\(.\).*/\1/')
if test "$STARTNUM" '!=' "$ENDNUM"; then
echo "Error: Numeral is different"
exit 1
fi
STARTLETTER=$(echo "$START" | sed 's/^.\(.\).*/\1/')
ENDLETTER=$(echo "$END" | sed 's/^.\(.\).*/\1/')
OUTPUT=''
for LETTER in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ; do
test "$LETTER" '==' "$STARTLETTER" && OUTPUT='yes'
test -n "$OUTPUT" && echo "$PART1, $STARTNUM$LETTER,$PART3"
test "$LETTER" '==' "$ENDLETTER" && OUTPUT=''
done
会做你需要的事情,尽管当用原始文本调用时性能不是很好$1
编辑
根据要求,关于表达的几句话sed
:
- 我
PART1
通过将空格和开头之前的所有内容进行隔离(
- 我从收盘
PART3
开始就把一切都隔离起来)
- 我通过获取和
PART2
之间的内容来隔离,忽略空格(
)
START
并由END
破折号分隔,同样忽略空格- 数字和字母通过第一和第二个字符来区分
答案2
如果 GNU sed 可用
sed -r 's/([^(]+) \((.)(.) - .(.)\)(.*)/printf \x27\1, \2%s,\5\\n\x27 {\3..\4}/e' <<<'Gene Code (1A - 1F) D2 fragment, D74F'
Gene Code, 1A, D2 fragment, D74F
Gene Code, 1B, D2 fragment, D74F
Gene Code, 1C, D2 fragment, D74F
Gene Code, 1D, D2 fragment, D74F
Gene Code, 1E, D2 fragment, D74F
Gene Code, 1F, D2 fragment, D74F
如果没有,则运行它作为管道发送到 shell
sed -r 's/([^(]+) \((.)(.) - .(.)\)(.*)/printf \x27\1, \2%s,\5\\n\x27 {\3..\4}/' <<<'Gene Code (1A - 1F) D2 fragment, D74F'|bash
Gene Code, 1A, D2 fragment, D74F
Gene Code, 1B, D2 fragment, D74F
Gene Code, 1C, D2 fragment, D74F
Gene Code, 1D, D2 fragment, D74F
Gene Code, 1E, D2 fragment, D74F
Gene Code, 1F, D2 fragment, D74F
(与sh
和 的ksh
输出相同)
答案3
perl 方式:
#!/usr/bin/perl
use feature 'say';
my $str = '"Gene Code (3D - 3H) D2 fragment, D74F"';
# get begin number, begin letter, end number, end letter
my ($bn,$bl,$en,$el) = $str =~ /\((.)(.) - (.)(.)\)/;
# loop from begin letter to end letter
for my $i ($bl .. $el) {
# do the substitution and print
($_ = $str) =~ s/ \(.. - ..\)/, $bn$i,/ && say;
}
输出:
"Gene Code, 3D, D2 fragment, D74F"
"Gene Code, 3E, D2 fragment, D74F"
"Gene Code, 3F, D2 fragment, D74F"
"Gene Code, 3G, D2 fragment, D74F"
"Gene Code, 3H, D2 fragment, D74F"
答案4
不需要循环的版本,仅使用四次 sed 调用。当然,我的版本不会检查两个数字是否相等。事实上,第二个数字会被忽略,甚至可以省略,就像 一样"Gene Code (91K - Q) D2 fragment, D74F"
。此外,下限和上限可以按任意顺序出现。如果下限大于上限,则输出顺序会反转。
$ cat foo
#!/usr/bin/env bash
# Script to expand $1 passed as:
# "Gene Code (91K - 91Q) D2 fragment, D74F"
#
# into the output:
#
# Gene Code, 91K, D2 fragment, D74F
# Gene Code, 91L, D2 fragment, D74F
# Gene Code, 91M, D2 fragment, D74F
# Gene Code, 91N, D2 fragment, D74F
# Gene Code, 91O, D2 fragment, D74F
# Gene Code, 91P, D2 fragment, D74F
# Gene Code, 91Q, D2 fragment, D74F
# Copy $1 into FMT_STRING, replacing the " (91K - 91Q)" bit with a ', %s,'
# printf directive, such as 'Gene Code, %s, D2 fragment, D74F':
FMT_STRING="$(sed -e 's/ (.* - .*)/, %s,/' <<< "$1")"
# Parse the beginning and ending bounds and format them with just a
# space between, such as '91K 91Q':
BOUNDS="$(sed -e 's/^[^(]*(\(.*\) - \(.*\)) .*/\1 \2/' <<< "$1")"
# Extract the (first) static numeric part from BOUNDS, e.g. '91'
NUMERIC="$(sed -e 's/[^0-9].*//' <<< "$BOUNDS")"
# remove all digits [0-9] from BOUNDS, e.g. 'K Q'
BOUNDS="$(sed -e 's/[0-9]//g' <<< "$BOUNDS")"
FMT_STRING="$(printf "$FMT_STRING" "${NUMERIC}%c")"
jot -w "$FMT_STRING" - $BOUNDS
示例输出:
$ ./foo "Gene Code (737L - 737X) D2 fragment, D74F"
Gene Code, 737L, D2 fragment, D74F
Gene Code, 737M, D2 fragment, D74F
Gene Code, 737N, D2 fragment, D74F
Gene Code, 737O, D2 fragment, D74F
Gene Code, 737P, D2 fragment, D74F
Gene Code, 737Q, D2 fragment, D74F
Gene Code, 737R, D2 fragment, D74F
Gene Code, 737S, D2 fragment, D74F
Gene Code, 737T, D2 fragment, D74F
Gene Code, 737U, D2 fragment, D74F
Gene Code, 737V, D2 fragment, D74F
Gene Code, 737W, D2 fragment, D74F
Gene Code, 737X, D2 fragment, D74F
反转边界会反转输出:
$ ./foo "Gene Code (737X - 737L) D2 fragment, D74F"
Gene Code, 737X, D2 fragment, D74F
Gene Code, 737W, D2 fragment, D74F
Gene Code, 737V, D2 fragment, D74F
Gene Code, 737U, D2 fragment, D74F
Gene Code, 737T, D2 fragment, D74F
Gene Code, 737S, D2 fragment, D74F
Gene Code, 737R, D2 fragment, D74F
Gene Code, 737Q, D2 fragment, D74F
Gene Code, 737P, D2 fragment, D74F
Gene Code, 737O, D2 fragment, D74F
Gene Code, 737N, D2 fragment, D74F
Gene Code, 737M, D2 fragment, D74F
Gene Code, 737L, D2 fragment, D74F