ISO8583中包含Unicode字符的域长度

4
Iso8583消息可以包含可变长度字段,例如字段44/an ..25/附加响应数据。目前我们根据字符长度计算这些字段,但是我们已经添加了对右双引号()和右单引号()的支持,这需要使用UTF-8。这些字符被编码为三个字节,这意味着字节长度和字符/字符串长度不再相等,这会导致一些流程出现错误。
我的问题是 - Iso8583标准是否要求字段长度是字节还是字符?
维基百科不一致,我找到的大多数其他来源都没有明确说明。

1
你需要计算传输字符串所使用的字节数组的二进制长度。实际上,在ISO8583中,除非你的规范明确允许使用Unicode或UTF,否则它们并不适用。 - iso8583.info support
我们支持FPS,它允许这两个utf/unicode字符,因此我们必须支持。在这种情况下,该字段的长度肯定是字节而不是字符吗?考虑到它是二进制格式,这是有道理的。 - appalling22
双引号 " 和单引号 ' 是否真正增加了任何商业价值?如果没有,将它们替换为 "' 可能更有意义,这样既可以避免此问题,还可以增加其他系统处理数据的可能性。 - Jeroen Mostert
" is 0x22,而 ' 是 0x27,两者都是 ASCII 码。在我所知道的所有 8583 变体中,“AN” 指定符限制您使用单字节字符集。你说这是二进制格式。那么,所讨论的字段是否使用“B”指定符?在这种情况下,长度几乎肯定以字节/八位字节为单位指定。如果某些提供商需要带有 UTF8/16 UCS ... 的畸形 AN 限定符,则您确实应该询问提供商,因为除非我们知道您正在谈论哪个 8583 变体,否则我们只能猜测。 - a2800276
@JeroenMostert 在FPS规范中不允许使用 '",只允许使用Unicode字符。但不幸的是,我们不得不支持它们,因为我们的一个客户支持它们并且它们被允许作为规范的一部分。而且我们不能将它们替换为安全字符,因为我们不应该对他们的请求进行任何更改。 - appalling22
从纯粹的观点出发,UTF-8 应该是用于处理单字节 ASCII 数据的系统的透明扩展(这是 ISO 8583 最初的来源),因此长度应该按代码点而不是字符计算,这样现有系统就可以将 视为三个“字符”,而无需理解它们即可传递。然而,如果您是专门为客户实施此功能,则应该与他们核实,因为如果您必须处理请求,例如,拒绝“过长”的请求将对您没有好处。 - Jeroen Mostert
2个回答

1

长度以字节为单位,从技术上讲,只要它适合字节数,就没有什么可以阻止您使用Unicode字符。 然而,这些消息经常在支付系统之间进行字符集转换,例如ASCII和EBCDIC。由于这些转换,Unicode字符并不总是能够被正确转换、支持或丢失。最糟糕的情况是会破坏整个过程。作为金融格式,数据丢失通常是不可接受的。

您应该避免使用非打印ASCII字符和任何大于十进制127(十六进制7F)的字符。还有一些问题字符,在ASCII和EBCDIC之间不能很好地清晰转换(请参见https://www.ibm.com/docs/en/iis/11.7?topic=tables-conversion-table-irregularities)。例如,EBCDIC | 转换为 ASCII !,而ASCII | 在使用标准转换表时无法很好地转换。

根据我的经验,以下ASCII字符表是安全的。

字符 十进制 十六进制
空格 32 20
& 38 26
' 39 27
* 42 2A
- 45 2D
. 46 2E
/ 47 2F
0 - 9 48 - 57 30 - 39
A - Z 65 - 90 41 - 5A
a - z 97 - 122 61 - 7A

0

如果您想在特殊字段中使用Unicode字符,ISO8583标准不会对此进行限制。

您可以开发一个新的字段解析器,该解析器获取字节流/数组并将其转换为字符串,然后将该字符串设置为字段数据,在C#中,只需将其转换为字符串即可(因为.net引擎使用Unicode作为其主要编码来存储字符串)

这里是一个使用OpenIso8583Net库的示例:

using System.Text;

namespace OpenIso8583Net.Formatter
{
    /// <summary>
    ///   UTF8 Field Formatter
    /// </summary>
    public class UTF8Formatter : IFormatter
    {
        #region IFormatter Members

        /// <summary>
        ///   Format the string and return as an encoded byte array
        /// </summary>
        /// <param name = "value">value to format</param>
        /// <returns>Encoded byte array</returns>
        public byte[] GetBytes(string value)
        {
            return Encoding.UTF8.GetBytes(value);
        }

        /// <summary>
        ///   Format the string and return as an encoded byte array
        /// </summary>
        /// <param name = "value">value to format</param>
        /// <param name="length"> </param>
        /// <returns>Encoded byte array</returns>
        public byte[] Pack(string value, int length)
        {
            return Encoding.UTF8.GetBytes(value.PadLeft(length, '0'));
        }

        /// <summary>
        ///   Length for UTF8 is not Implemented Completely!
        ///   Format the string and return as an encoded byte array 
        /// </summary>
        /// <param name = "value">value to format</param>
        /// <param name="length"> </param>
        /// <returns>Encoded byte array</returns>
        public byte[] GetBytes(string value, int length)
        {
            return Encoding.UTF8.GetBytes(value);
        }

        /// <summary>
        ///   Takes the byte array and converts it to a string for use
        /// </summary>
        /// <param name = "data">Data to convert</param>
        /// <returns>Converted data</returns>
        public string GetString(byte[] data)
        {
            return Encoding.UTF8.GetString(data);
        }

        /// <summary>
        ///   Gets the packed length of the data given the unpacked length
        /// </summary>
        /// <param name = "unpackedLength">Unpacked length</param>
        /// <returns>Packed length of the data</returns>
        public int GetPackedLength(int unpackedLength)
        {
            return unpackedLength;
        }

        #endregion
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接