使用 bash 脚本从句子中删除超过 [x] 个字符的单词
Using bash script to remove from sentence words longer than [x] characters
我有一个句子(数组),我想从中删除所有超过 8 个字符的单词。
例句:
var="one two three four giberish-giberish five giberish-giberish six"
我想得到:
var="one two three four five six"
到目前为止我正在使用这个:
echo $var | tr ' ' '\n' | awk 'length() <= 6 { print }' | tr '\n ' ' '
上面的解决方案工作正常,但如您所见,我将 space 替换为换行符,然后过滤单词,然后将换行符替换为 space。我很确定必须有更好更“优雅”的解决方案而不交换 space/newline.
这是一种方法:
arr=(one two three four giberish-giberish five giberish-giberish six)
for var in "${arr[@]}"; do (( ${#var} > 8 )) || echo -n "$var "; done
echo # for that newline in the end
还有一个:
awk '{ for(i=1;i<=NF;i++) { if(length($i) < 8) printf "%s ", $i } print "" # for that newline in the end }'
还有第三个!
awk -v RS='[[:space:]]+' 'length < 8 { v=v" "[=12=] }; END{print substr(v, 2)}'
最后一个打印一个“完美”的 single-space 分隔字符串,没有额外的前导或尾随空格。
你可以使用
#!/bin/bash
var="one two three four giberish-giberish five giberish-giberish six"
awk 'BEGIN{RS=ORS=" "} length([=10=]) <= 6' <<< "$var"
# -> one two three four five six
参见online demo。
BEGIN{RS=ORS=" "}
将记录 input/output 分隔符设置为 space 并且 length([=14=]) <= 6
仅保留等于或小于 6 个字符的字段。
您还可以考虑使用 GNU sed
和 perl
的解决方法:
sed -E 's/\s*\S{7,}//g' <<< "$var"
perl -pe 's/\s*\S{7,}//g' <<< "$var"
参见 this online demo。
non-GNU sed 解决方法可能类似于
sed 's/[[:space:]]*[^[:space:]]\{7,\}//g' <<< "$var"
此处,所有出现零个或多个白色space(\s*
、[[:space:]]*
)后跟七个或更多non-whitespace个字符(\S{7,}
、 [^[:space:]]\{7,\}
) 被删除。
使用sed
$ sed 's/\<[a-z-]\{8,\}\> //g' file
var="one two three four five six"
在纯 Bash 中,您可以将小于选定长度的单词过滤到一个新数组中:
#!/bin/bash
var="one two three four giberish-giberish five giberish-giberish six"
new_arr=()
for w in $var; do # no quotes on purpose to split string
[[ ${#w} -lt 6 ]] && new_arr+=( "$w" )
done
declare -p new_arr
# declare -a new_arr=([0]="one" [1]="two" [2]="three" [3]="four" [4]="five" [5]="six")
或者如果源已经是一个数组:
old_arr=(one two three four giberish-giberish five giberish-giberish six)
new_arr=()
for w in ${old_arr[@]}; do
[[ ${#w} -lt 6 ]] && new_arr+=( "$w" )
done
您可能希望在遍历 old_arr
时删除其中的单词。如果你知道每个 $w
都是独一无二的,你可以这样做:
old_arr=(one two three four giberish-giberish five giberish-giberish six)
for w in ${old_arr[@]}; do
[[ ${#w} -ge 6 ]] && old_arr=("${old_arr[@]/$w}")
done
但这有两个问题:1) 如果你有相同的前缀,所有将被删除和 2) 现有索引将保留:
$ declare -p old_arr
declare -a old_arr=([0]="one" [1]="two" [2]="three" [3]="four" [4]="" [5]="five" [6]="" [7]="six")
您还可以 unset
通过保留单独的索引来违规项目:
old_arr=(one two three four giberish-giberish five giberish-giberish six)
idx=0
for w in ${old_arr[@]}; do
[[ ${#w} -ge 6 ]] && unset 'old_arr[idx]'
(( idx++ ))
done
但是你最终会得到不连续的数组索引(但现有的限定词仍然在同一索引处):
$ declare -p old_arr
declare -a old_arr=([0]="one" [1]="two" [2]="three" [3]="four" [5]="five" [7]="six")
通常过滤到新数组中更好,除非您想保留现有索引。
这可能对你有用 (GNU sed):
<<<"$var" sed -E 'y/ /\n/;s/..{8}.*\n//mg;y/\n/ /'
将空格转换为换行符。
删除所有长度超过 8 个字符的行。
将换行符转换为空格。
我有一个句子(数组),我想从中删除所有超过 8 个字符的单词。
例句:
var="one two three four giberish-giberish five giberish-giberish six"
我想得到:
var="one two three four five six"
到目前为止我正在使用这个:
echo $var | tr ' ' '\n' | awk 'length() <= 6 { print }' | tr '\n ' ' '
上面的解决方案工作正常,但如您所见,我将 space 替换为换行符,然后过滤单词,然后将换行符替换为 space。我很确定必须有更好更“优雅”的解决方案而不交换 space/newline.
这是一种方法:
arr=(one two three four giberish-giberish five giberish-giberish six)
for var in "${arr[@]}"; do (( ${#var} > 8 )) || echo -n "$var "; done
echo # for that newline in the end
还有一个:
awk '{ for(i=1;i<=NF;i++) { if(length($i) < 8) printf "%s ", $i } print "" # for that newline in the end }'
还有第三个!
awk -v RS='[[:space:]]+' 'length < 8 { v=v" "[=12=] }; END{print substr(v, 2)}'
最后一个打印一个“完美”的 single-space 分隔字符串,没有额外的前导或尾随空格。
你可以使用
#!/bin/bash
var="one two three four giberish-giberish five giberish-giberish six"
awk 'BEGIN{RS=ORS=" "} length([=10=]) <= 6' <<< "$var"
# -> one two three four five six
参见online demo。
BEGIN{RS=ORS=" "}
将记录 input/output 分隔符设置为 space 并且 length([=14=]) <= 6
仅保留等于或小于 6 个字符的字段。
您还可以考虑使用 GNU sed
和 perl
的解决方法:
sed -E 's/\s*\S{7,}//g' <<< "$var"
perl -pe 's/\s*\S{7,}//g' <<< "$var"
参见 this online demo。
non-GNU sed 解决方法可能类似于
sed 's/[[:space:]]*[^[:space:]]\{7,\}//g' <<< "$var"
此处,所有出现零个或多个白色space(\s*
、[[:space:]]*
)后跟七个或更多non-whitespace个字符(\S{7,}
、 [^[:space:]]\{7,\}
) 被删除。
使用sed
$ sed 's/\<[a-z-]\{8,\}\> //g' file
var="one two three four five six"
在纯 Bash 中,您可以将小于选定长度的单词过滤到一个新数组中:
#!/bin/bash
var="one two three four giberish-giberish five giberish-giberish six"
new_arr=()
for w in $var; do # no quotes on purpose to split string
[[ ${#w} -lt 6 ]] && new_arr+=( "$w" )
done
declare -p new_arr
# declare -a new_arr=([0]="one" [1]="two" [2]="three" [3]="four" [4]="five" [5]="six")
或者如果源已经是一个数组:
old_arr=(one two three four giberish-giberish five giberish-giberish six)
new_arr=()
for w in ${old_arr[@]}; do
[[ ${#w} -lt 6 ]] && new_arr+=( "$w" )
done
您可能希望在遍历 old_arr
时删除其中的单词。如果你知道每个 $w
都是独一无二的,你可以这样做:
old_arr=(one two three four giberish-giberish five giberish-giberish six)
for w in ${old_arr[@]}; do
[[ ${#w} -ge 6 ]] && old_arr=("${old_arr[@]/$w}")
done
但这有两个问题:1) 如果你有相同的前缀,所有将被删除和 2) 现有索引将保留:
$ declare -p old_arr
declare -a old_arr=([0]="one" [1]="two" [2]="three" [3]="four" [4]="" [5]="five" [6]="" [7]="six")
您还可以 unset
通过保留单独的索引来违规项目:
old_arr=(one two three four giberish-giberish five giberish-giberish six)
idx=0
for w in ${old_arr[@]}; do
[[ ${#w} -ge 6 ]] && unset 'old_arr[idx]'
(( idx++ ))
done
但是你最终会得到不连续的数组索引(但现有的限定词仍然在同一索引处):
$ declare -p old_arr
declare -a old_arr=([0]="one" [1]="two" [2]="three" [3]="four" [5]="five" [7]="six")
通常过滤到新数组中更好,除非您想保留现有索引。
这可能对你有用 (GNU sed):
<<<"$var" sed -E 'y/ /\n/;s/..{8}.*\n//mg;y/\n/ /'
将空格转换为换行符。
删除所有长度超过 8 个字符的行。
将换行符转换为空格。