biip icon indicating copy to clipboard operation
biip copied to clipboard

Failed to match pattern on GSI UDI Datamatrix

Open clam0r opened this issue 1 year ago • 1 comments

Hello!

I tried parsing data from the following barcode and revieved the following error:

Failed to match '158993a' with GS1 AI (15) pattern '^15(\d{6})$'.

Barcode:

  • Data: 0104150011164140211GTFG32DLF1723033110158993A

grafik

I tried parsing with the following code:

def parse_udi(udi):
        print("parse udi")
        print(udi)

        result = GS1Message.parse(udi)
        
        print(result)

        print(result.get(ai="17"))
        print(result.get(ai="10"))

Other Barcodes like 0104046963351946172401011019A21G8345 are working fine! grafik

It seems like the parser runs into an error with the (21) AI. Using the same faulty barcode string without the (21) AI works fine 01041500111641401723033110158993A

I tried looking into https://github.com/jodal/biip/issues/113 and https://github.com/jodal/biip/issues/137 but didnt get any clues that helped me.

Edit

Another barcode with the (21) AI seems to work partialy.

grafik

01041500111641401726013110V1002521JGFMG4P38R gets parsed successfully but returns

GS1ElementString(ai=GS1ApplicationIdentifier(ai='10', description='Batch or lot number', data_title='BATCH/LOT', fnc1_required=True, format='N2+X..20'), value='V1002521JGFMG4P38R', pattern_groups=['V1002521JGFMG4P38R'], gln=None, gln_error=None, gtin=None, gtin_error=None, sscc=None, sscc_error=None, date=None, decimal=None, money=None) where the (21) AI is located in the (10) AI:

  • V1002521JGFMG4P38R

clam0r avatar Jan 02 '24 22:01 clam0r

First, thank you for taking the time to include photos of the barcodes in question. That makes it a lot easier to help you!

The root of the problems you are seeing is variable-length fields. These are separated by a special character called "FNC1", often encoded as the byte 0x1D ("Group Separator" or "GS" in the ASCII table). Most barcode scanners can be configured to emit another character when they read a FNC1 character. I've often configured them to emit | (pipe) instead, as that character cannot legally appear in barcodes with GS1-128 data.

I tested all of your barcodes with the Android app "Barcode Scanner" from "Cognex Corporation". This app is helpful because it inserts a space when it sees a FNC1 character.

Here's the output from the Android app:

0104150011164140211GTFG32DLF 1723033110158993A
0104046963351946172401011019A21G8345
01041500111641401726013110V10025 21JGFMG4P38R

As you can see, the second barcode doesn't have any variable length fields and thus no FNC1 character, explaining why you were able to parse that one correctly.

Replacing the spaces with pipes, as space can legally appear in some GS1-128 elements, and passing the strings to Biip, specifying that | is the separator character to look for, we can parse the barcodes successfully:

>>> import biip
>>> import pprint
>>> pprint.pprint(biip.parse("0104150011164140211GTFG32DLF|1723033110158993A", separator_chars=["|"]).gs1_message.element_st
rings)
[GS1ElementString(ai=GS1ApplicationIdentifier(ai='01',
                                              description='Global Trade Item '
                                                          'Number (GTIN)',
                                              data_title='GTIN',
                                              fnc1_required=False,
                                              format='N2+N14'),
                  value='04150011164140',
                  pattern_groups=['04150011164140'],
                  gln=None,
                  gln_error=None,
                  gtin=Gtin(value='04150011164140',
                            format=GtinFormat.GTIN_13,
                            prefix=GS1Prefix(value='415', usage='GS1 Germany'),
                            company_prefix=GS1CompanyPrefix(value='415001116414'),
                            payload='415001116414',
                            check_digit=0,
                            packaging_level=None),
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=None,
                  decimal=None,
                  money=None),
 GS1ElementString(ai=GS1ApplicationIdentifier(ai='21',
                                              description='Serial number',
                                              data_title='SERIAL',
                                              fnc1_required=True,
                                              format='N2+X..20'),
                  value='1GTFG32DLF',
                  pattern_groups=['1GTFG32DLF'],
                  gln=None,
                  gln_error=None,
                  gtin=None,
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=None,
                  decimal=None,
                  money=None),
 GS1ElementString(ai=GS1ApplicationIdentifier(ai='17',
                                              description='Expiration date '
                                                          '(YYMMDD)',
                                              data_title='USE BY OR EXPIRY',
                                              fnc1_required=False,
                                              format='N2+N6'),
                  value='230331',
                  pattern_groups=['230331'],
                  gln=None,
                  gln_error=None,
                  gtin=None,
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=datetime.date(2023, 3, 31),
                  decimal=None,
                  money=None),
 GS1ElementString(ai=GS1ApplicationIdentifier(ai='10',
                                              description='Batch or lot number',
                                              data_title='BATCH/LOT',
                                              fnc1_required=True,
                                              format='N2+X..20'),
                  value='158993A',
                  pattern_groups=['158993A'],
                  gln=None,
                  gln_error=None,
                  gtin=None,
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=None,
                  decimal=None,
                  money=None)]
>>> pprint.pprint(biip.parse("0104046963351946172401011019A21G8345", separator_chars=["|"]).gs1_message.element_strings)
[GS1ElementString(ai=GS1ApplicationIdentifier(ai='01',
                                              description='Global Trade Item '
                                                          'Number (GTIN)',
                                              data_title='GTIN',
                                              fnc1_required=False,
                                              format='N2+N14'),
                  value='04046963351946',
                  pattern_groups=['04046963351946'],
                  gln=None,
                  gln_error=None,
                  gtin=Gtin(value='04046963351946',
                            format=GtinFormat.GTIN_13,
                            prefix=GS1Prefix(value='404', usage='GS1 Germany'),
                            company_prefix=GS1CompanyPrefix(value='4046963'),
                            payload='404696335194',
                            check_digit=6,
                            packaging_level=None),
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=None,
                  decimal=None,
                  money=None),
 GS1ElementString(ai=GS1ApplicationIdentifier(ai='17',
                                              description='Expiration date '
                                                          '(YYMMDD)',
                                              data_title='USE BY OR EXPIRY',
                                              fnc1_required=False,
                                              format='N2+N6'),
                  value='240101',
                  pattern_groups=['240101'],
                  gln=None,
                  gln_error=None,
                  gtin=None,
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=datetime.date(2024, 1, 1),
                  decimal=None,
                  money=None),
 GS1ElementString(ai=GS1ApplicationIdentifier(ai='10',
                                              description='Batch or lot number',
                                              data_title='BATCH/LOT',
                                              fnc1_required=True,
                                              format='N2+X..20'),
                  value='19A21G8345',
                  pattern_groups=['19A21G8345'],
                  gln=None,
                  gln_error=None,
                  gtin=None,
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=None,
                  decimal=None,
                  money=None)]
>>> pprint.pprint(biip.parse("01041500111641401726013110V10025|21JGFMG4P38R", separator_chars=["|"]).gs1_message.element_str
ings)
[GS1ElementString(ai=GS1ApplicationIdentifier(ai='01',
                                              description='Global Trade Item '
                                                          'Number (GTIN)',
                                              data_title='GTIN',
                                              fnc1_required=False,
                                              format='N2+N14'),
                  value='04150011164140',
                  pattern_groups=['04150011164140'],
                  gln=None,
                  gln_error=None,
                  gtin=Gtin(value='04150011164140',
                            format=GtinFormat.GTIN_13,
                            prefix=GS1Prefix(value='415', usage='GS1 Germany'),
                            company_prefix=GS1CompanyPrefix(value='415001116414'),
                            payload='415001116414',
                            check_digit=0,
                            packaging_level=None),
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=None,
                  decimal=None,
                  money=None),
 GS1ElementString(ai=GS1ApplicationIdentifier(ai='17',
                                              description='Expiration date '
                                                          '(YYMMDD)',
                                              data_title='USE BY OR EXPIRY',
                                              fnc1_required=False,
                                              format='N2+N6'),
                  value='260131',
                  pattern_groups=['260131'],
                  gln=None,
                  gln_error=None,
                  gtin=None,
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=datetime.date(2026, 1, 31),
                  decimal=None,
                  money=None),
 GS1ElementString(ai=GS1ApplicationIdentifier(ai='10',
                                              description='Batch or lot number',
                                              data_title='BATCH/LOT',
                                              fnc1_required=True,
                                              format='N2+X..20'),
                  value='V10025',
                  pattern_groups=['V10025'],
                  gln=None,
                  gln_error=None,
                  gtin=None,
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=None,
                  decimal=None,
                  money=None),
 GS1ElementString(ai=GS1ApplicationIdentifier(ai='21',
                                              description='Serial number',
                                              data_title='SERIAL',
                                              fnc1_required=True,
                                              format='N2+X..20'),
                  value='JGFMG4P38R',
                  pattern_groups=['JGFMG4P38R'],
                  gln=None,
                  gln_error=None,
                  gtin=None,
                  gtin_error=None,
                  sscc=None,
                  sscc_error=None,
                  date=None,
                  decimal=None,
                  money=None)]

For another explanation of this, see the Variable-length fields section in the docs.

jodal avatar Jan 13 '24 21:01 jodal

As I haven't heard back from you, I'm closing this issue. Feel free to start a discussion (as opposed to an issue) if you need further help with this.

jodal avatar Jul 29 '24 16:07 jodal