源文件在每一行的开头都有一个特殊字符。文件以双空格分隔。
样本数据文件:
âNAME ABC
âAGE 21
âADDRESS XYZ street ABC city
âCONTACT 13244235
âDOJ 20181212
我想删除â
每行中的第一个特殊字符,并将文件转换为;
(分号)分隔的文件。
我编写的以下代码在 UAT 中工作正常,但在 PROD 中无法正常工作:
awk '{ print substr($0,1) }' FILE1.txt | sed 's/ /;/' > FILE2.txt
UAT输出(预期的期望输出):
NAME;ABC
AGE;21
ADDRESS;XYZ street ABC city
CONTACT;13244235
DOJ;20181212
产品输出:
âNAME;ABC
âAGE;21
âADDRESS;XYZ street ABC city
âCONTACT;13244235
âDOJ;20181212
相同的代码在 UAT 中工作正常,即删除第一个字符并将文件转换为;
分号分隔,但在 PROD 中它不会删除第一个特殊字符,而是将文件转换为分号分隔。
输出locale
:
locale
LANG=en_US.UTF-8
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=
谁能帮我解决这个问题..?
答案1
我认为你的问题可能是链接到字符编码,尝试FILE1.txt
在两个环境中显示
hexdump -C FILE1.txt
它可以编码为 E-ascii 或 UTF-8(请参阅https://en.wikipedia.org/wiki/%C3%82#Character_mappings)
要解决您的问题,您可以尝试匹配两种编码:
â in UTF-8 â in other encoding
| |
v v
sed 's/\xc3\xa2//' FILE1.txt | sed 's/\xE2//' > FILE2.txt
另一种解决方案可能是在处理文件之前将文件转换为已知编码。
不测试 PROD 编码可能会很危险。
答案2
由于â
您看到的几乎肯定是编码问题,并且假设所有行都应该以大写字母开头,您可以尝试以下操作:
LC_ALL=C sed 's/^[^A-Z]*//; s/ */;/g' FILE1.txt > FILE2
这将使用区域设置运行命令,C
该区域设置应确保您的任何字符â
都不包含在 AZ 范围内。然后,sed 命令简单地从每行开头删除所有不在 AZ 范围内的字符,然后将所有出现的两个或多个空格转换为;
.
答案3
尝试
sed 's/^â//; s/ */;/g' FILE1.txt > FILE2.txt
如果它不适合你,请投反对票
答案4
要删除每行的第一个字符,应该是:
cut -c2- # not with the GNU implementation which is currently not multi-byte aware
sed 's/^.//'
awk '{print substr($0, 2)}' # note the 2 instead of 1 as offsets are 1-based
# not with mawk or other non-multi-byte aware awk
# implementations.
但请注意,为了.
匹配该â
字符并substr()
正常工作,â
必须根据区域设置的编码对其进行编码(请参阅 的输出locale charmap
)。
要删除第一个字符并将所有空白序列替换为;
,您可以执行以下操作:
sed 's/^.//;s/[[:space:]]\{1,\}/;/g'
或者:
awk -v OFS=';' '{$0 = substr($0, 2); $1 = $1; print}'
(但请注意,后者不会包含;
以空白字符结尾的行的尾随,并且被视为分隔符的空白字符列表因awk
实现和区域设置而异)。
现在,还要注意â
(U+00E2) 在 iso8859-1 字符集(也称为latin1
和其他一些单字节字符集)中被编码为字节 0xe2。而那个字节 0xe2 也恰好是多个 3 字节 UTF-8 字符编码的第一个字节,其中有几个 Unicode 空白字符(如 U+2000 到 U+200B 空格字符)。
因此,如果您在 latin1 终端中看到â
显示,则输入实际上可能包含 U+2002 (EN SPACE),例如以 UTF-8 (0xe2 0x80 0x82) 编码,并且您的终端会将其显示0xe2
为â
和不会显示任何不在 latin1 中的 0x80 和 0x82。
要摆脱 EN SPACE,您需要剥离 1 个字符作为 UTF-8 语言环境,或者剥离 3 个单字节语言环境字符(例如使用 latin1 或 C 语言环境的字符)。