首页 > 解决方案 > 如何使用 sed 表达式用单宽替换双宽字符

问题描述

sed我想使用表达式将文件中的某些双宽字符替换为它们的单宽等效字符。这并不像预期的那样工作,但表达了我想要做的事情(这是在 bash 脚本中):我已经将字母数字范围与我能想到的其他一些混合在一起,不确定是否需要将其分成-e基于 if 范围等的两个不同参数。

sed -e 's,[0-9a-zA-Z()【】-一],[0-9a-zA-Z\(\)\[\]\-\-],g' ${file} > ${file}.cleaned

这些文件是 tsv(制表符分隔值)文本文件。根据file命令类型是:UTF-8 Unicode text, with CRLF line terminators或(在另一种情况下)UTF-8 Unicode text, with no line terminators

样本输入:

Part Number
123-956-AA
343-213-【E】
XTE-898一(5)

样本输出:

Part Number
123-956-AA
343-213-[E]
XTE-898-(5)

我的系统是在 Docker 容器中运行的 Ubuntu16.04,该容器是从我们的基础镜像构建的,phusion/passenger-ruby23:0.9.19该容器具有一个基础镜像(最终到基础)ubuntu:16.04,shell 是GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu),sed 版本是sed (GNU sed) 4.2.2locale命令的结果是:

LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

更新:

选择的解决方案/答案是 1) 使用y命令(正如其他答案也建议的那样),在我的情况下,2) 如下所示设置 LL_ALL 以避免我使用y命令时遇到的错误。似乎该范围不适用于该y命令,因此必须单独识别所有字符(正如我之前错误地认为的那样)

LC_ALL=en_US.UTF-8 sed 'y/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890()【】-一/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890()[]--' file.tsv

更新 2:

根据其他回答者的建议(其中一个神秘地消失了),为系统设置的语言环境作为一种解决方案被进一步调查,而不是在命令行中设置环境变量。由于这是一个 Docker 镜像容器环境,我找到了一个可以放入我们的基础镜像的解决方案,它解决了基础系统级别的问题。

我已经添加到我们的基础 Dockerfile 中:

# Set the locale
RUN locale-gen en_US.UTF-8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'

现在locale命令产生;

LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8

现在该sed命令的工作方式如下:

sed 'y/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890()【】-一/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890()[]--' file.tsv

作为旁注,我希望 stackoverflow 提供了一种将答案归功于多个答案的方法,因为最初的 3 个答案(同样,一个消失了)都让我得到了解决方案,但我只能选择一个。这种情况经常发生。

标签: regexubuntudockersedlocale

解决方案


如果perl没问题:

$ perl -Mopen=locale -Mutf8 -pe 'tr/0-9a-zA-Z()【】-一/0-9a-zA-Z()[]--/' ip.txt
Part Number
123-956-AA
343-213-[E]
XTE-898-(5)
  • -Mopen=locale -Mutf8将语言环境指定为utf8
  • tr/0-9a-zA-Z()【】-一/0-9a-zA-Z()[]--/根据需要翻译字符,也可以使用y代替tr


sed (GNU sed) 4.2.2可以使用,但不支持范围

$ # simulating OP's POSIX locale
$ echo '91A9foo' | LC_ALL=C sed 'y/A9/A9/'
sed: -e expression #1, char 12: strings for `y' command are different lengths

$ # changing to a utf8 locale
$ echo '91A9foo' | LC_ALL=en_US.UTF-8 sed 'y/A9/A9/'
91A9foo

进一步阅读:https ://wiki.archlinux.org/index.php/locale


推荐阅读