import Foundation
let pattern = #"\{(?:(?<!ToolTipML)[^}])+\}"#
let regex = try! NSRegularExpression(pattern: pattern, options: .anchorsMatchLines)
let testString = ##"""
{ 66 ;3 ;Field ;
ToolTipML=[ENU=Specifies the language to be used on printouts for this customer.;
ENG=Specifies the language to be used on printouts for this customer.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Language Code";
Importance=Additional }
{ 1000000087;3;Field ;
SourceExpr="Created By";
Importance=Additional }
{ 1000000090;3;Field ;
SourceExpr="Creation Date";
Importance=Additional }
{ 1000000007;3;Field ;
CaptionML=[ENU=Bill-To Alert;
ENG=Bill-To Alert];
ToolTipML=[ENU=Illuminates when invoices are paid by another customer (the Bill-to).;
ENG=Illuminates when invoices are paid by another customer (the Bill-to).];
SourceExpr=BillToText;
Editable=FALSE;
Style=Unfavorable;
StyleExpr=TRUE }
{ 1000000011;3;Field ;
ToolTipML=[ENU=Default Contact for the Accounts Department, selected from the Contact List.;
ENG=Default Contact for the Accounts Department, selected from the Contact List.];
SourceExpr="Accounts Contact No." }
{ 1000000010;3;Field ;
ToolTipML=[ENU=Specifies the accounts contact name for the customer.;
ENG=Specifies the accounts contact name for the customer.];
SourceExpr="Accounts Contact Name" }
{ 1000000009;3;Field ;
ToolTipML=[ENU=Specifies the customer's alternate telephone number. Synchronized with the Contact Card.;
ENG=Specifies the customer's alternate telephone number. Synchronized with the Contact Card.];
SourceExpr="Phone 2";
Importance=Additional }
{ 1000000008;3;Field ;
ToolTipML=[ENU=Specifies the customer's alternate fax number. Synchronized with the Contact Card.;
ENG=Specifies the customer's alternate fax number. Synchronized with the Contact Card.];
SourceExpr="Fax 2";
Importance=Additional }
{ 1905885101;1;Group ;
CaptionML=[ENU=Invoicing;
ENG=Invoicing] }
{ 34 ;2 ;Field ;
CaptionML=[ENU=Bill-to Customer;
ENG=Bill-to Customer];
ToolTipML=[ENU=Specifies a different customer who will be invoiced for products that you sell to the customer in the Name field on the customer card.;
ENG=Specifies a different customer who will be invoiced for products that you sell to the customer in the Name field on the customer card.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Bill-to Customer No.";
Importance=Additional }
{ 1000000041;2;Field ;
CaptionML=[ENU=Bill-to Customer Name;
ENG=Bill-to Customer Name];
SourceExpr=BillToName;
Importance=Promoted;
Editable=FALSE }
{ 29 ;2 ;Field ;
ToolTipML=[ENU=Specifies the customer's VAT registration number for customers in EU countries/regions.;
ENG=Specifies the customer's VAT registration number for customers in EU countries/regions.];
ApplicationArea=#Basic,#Suite;
SourceExpr="VAT Registration No.";
OnDrillDown=VAR
VATRegistrationLogMgt@1000 : Codeunit 249;
BEGIN
VATRegistrationLogMgt.AssistEditCustomerVATReg(Rec);
END;
}
{ 61 ;2 ;Field ;
ToolTipML=[ENU=Specifies the customer in connection with electronic document sending.;
ENG=Specifies the customer in connection with electronic document sending.];
ApplicationArea=#Basic,#Suite;
SourceExpr=GLN;
Importance=Additional }
{ 156 ;2 ;Field ;
ToolTipML=[ENU=Specifies which customer address is inserted on sales quotes that you create for the customer.;
ENG=Specifies which customer address is inserted on sales quotes that you create for the customer.];
ApplicationArea=#Advanced;
SourceExpr="Copy Sell-to Addr. to Qte From";
Importance=Additional }
{ 1000000095;2;Field ;
ToolTipML=[ENU=The INCO trading terms used by the customer.;
ENG=The INCO trading terms used by the customer.];
SourceExpr="Incoterms Code" }
{ 36 ;2 ;Field ;
ToolTipML=[ENU=Specifies how many copies of an invoice for the customer will be printed at a time.;
ENG=Specifies how many copies of an invoice for the customer will be printed at a time.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Invoice Copies";
Importance=Additional }
{ 170 ;2 ;Group ;
Name=PostingDetails;
CaptionML=[ENU=Posting Details;
ENG=Posting Details];
GroupType=Group }
{ 70 ;3 ;Field ;
ToolTipML=[ENU=Specifies the customer's trade type to link transactions made for this customer with the appropriate general ledger account according to the general posting setup.;
ENG=Specifies the customer's trade type to link transactions made for this customer with the appropriate general ledger account according to the general posting setup.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Gen. Bus. Posting Group";
Importance=Promoted;
ShowMandatory=TRUE }
{ 58 ;3 ;Field ;
ToolTipML=[ENU=Specifies the customer's VAT specification to link transactions made for this customer to.;
ENG=Specifies the customer's VAT specification to link transactions made for this customer to.];
ApplicationArea=#Basic,#Suite;
SourceExpr="VAT Bus. Posting Group";
Importance=Additional }
{ 38 ;3 ;Field ;
ToolTipML=[ENU=Specifies the customer's market type to link business transactions to.;
ENG=Specifies the customer's market type to link business transactions to.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Customer Posting Group";
Importance=Promoted;
ShowMandatory=TRUE }
{ 68 ;2 ;Group ;
Name=PricesandDiscounts;
CaptionML=[ENU=Prices and Discounts;
ENG=Prices and Discounts];
GroupType=Group }
{ 1000000015;3;Field ;
ToolTipML=[ENU=Specifies whether the customer is a member of a Buying Group.;
ENG=Specifies whether the customer is a member of a Buying Group.];
SourceExpr="Buying Group Code" }
{ 40 ;3 ;Field ;
ToolTipML=[ENU=Specifies the customer price group code, which you can use to set up special sales prices in the Sales Prices window.;
ENG=Specifies the customer price group code, which you can use to set up special sales prices in the Sales Prices window.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Customer Price Group";
Importance=Promoted }
{ 44 ;3 ;Field ;
ToolTipML=[ENU=Specifies the customer discount group code, which you can use as a criterion to set up special discounts in the Sales Line Discounts window.;
ENG=Specifies the customer discount group code, which you can use as a criterion to set up special discounts in the Sales Line Discounts window.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Customer Disc. Group";
Importance=Promoted }
{ 46 ;3 ;Field ;
ToolTipML=[ENU=Specifies if a sales line discount is calculated when a special sales price is offered according to setup in the Sales Prices window.;
ENG=Specifies if a sales line discount is calculated when a special sales price is offered according to setup in the Sales Prices window.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Allow Line Disc.";
Importance=Additional }
{ 1000000016;3;Field ;
ToolTipML=[ENU=Allows Break Quantity discounts for an Assortment (or Basket) of Items. If a Total Quantity of a defined Item Discount Group is purchased then a Discount applies.;
ENG=Allows Break Quantity discounts for an Assortment (or Basket) of Items. If a Total Quantity of a defined Item Discount Group is purchased then a Discount applies.];
SourceExpr="Allow Assorted Discount" }
{ 42 ;3 ;Field ;
ToolTipML=[ENU=Specifies a code for the invoice discount terms that you have defined for the customer.;
ENG=Specifies a code for the invoice discount terms that you have defined for the customer.];
ApplicationArea=#Basic,#Suite;
NotBlank=Yes;
SourceExpr="Invoice Disc. Code";
Importance=Additional }
{ 129 ;3 ;Field ;
ToolTipML=[ENU=Specifies if the Unit Price and Line Amount fields on document lines should be shown with or without VAT.;
ENG=Specifies if the Unit Price and Line Amount fields on document lines should be shown with or without VAT.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Prices Including VAT";
Importance=Additional }
{ 1901677601;1;Group ;
CaptionML=[ENU=Payments;
ENG=Payments] }
{ 160 ;2 ;Field ;
ToolTipML=[ENU=Specifies a prepayment percentage that applies to all orders for this customer, regardless of the items or services on the order lines.;
ENG=Specifies a prepayment percentage that applies to all orders for this customer, regardless of the items or services on the order lines.];
ApplicationArea=#Prepayments;
SourceExpr="Prepayment %";
Importance=Additional }
{ 48 ;2 ;Field ;
ToolTipML=[ENU=Specifies how to apply payments to entries for this customer.;
ENG=Specifies how to apply payments to entries for this customer.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Application Method";
Importance=Additional }
{ 21 ;2 ;Field ;
ToolTipML=[ENU=Specifies for direct debit collections if the customer that the payment is collected from is a person or a company.;
ENG=Specifies for direct debit collections if the customer that the payment is collected from is a person or a company.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Partner Type";
Importance=Additional }
{ 50 ;2 ;Field ;
ToolTipML=[ENU=Specifies a code that indicates the payment terms that you require of the customer.;
ENG=Specifies a code that indicates the payment terms that you require of the customer.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Payment Terms Code";
Importance=Promoted;
ShowMandatory=TRUE }
{ 1000000018;2;Field ;
ToolTipML=[ENU=Date Formula. Overrides default Grace Period Calculation. Populated from Payment Terms.;
ENG=Date Formula. Overrides default Grace Period Calculation. Populated from Payment Terms.];
SourceExpr="Grace Period Calculation" }
{ 11 ;2 ;Field ;
ToolTipML=[ENU=Specifies how the customer usually submits payment, such as bank transfer or check.;
ENG=Specifies how the customer usually submits payment, such as bank transfer or cheque.];
ApplicationArea=#Basic,#Suite;
SourceExpr="Payment Method Code";
Importance=Additional }
{ 15 ;2 ;Field ;
ToolTipML=[ENU=Specifies how reminders about late payments are handled for this customer.;
ENG=Specifies how reminders about late payments are handled for this customer.];
ApplicationArea=#Advanced;
SourceExpr="Reminder Terms Code";
Importance=Additional }
{ 52 ;2 ;Field ;
ToolTipML=[ENU=Specifies finance charges are calculated for the customer.;
ENG=Specifies finance charges are calculated for the customer.];
ApplicationArea=#Advanced;
SourceExpr="Fin. Charge Terms Code";
"""##
let stringRange = NSRange(location: 0, length: testString.utf16.count)
let matches = regex.matches(in: testString, range: stringRange)
var result: [[String]] = []
for match in matches {
var groups: [String] = []
for rangeIndex in 1 ..< match.numberOfRanges {
let nsRange = match.range(at: rangeIndex)
guard !NSEqualRanges(nsRange, NSMakeRange(NSNotFound, 0)) else { continue }
let string = (testString as NSString).substring(with: nsRange)
groups.append(string)
}
if !groups.isEmpty {
result.append(groups)
}
}
print(result)
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for Swift 5.2, please visit: https://developer.apple.com/documentation/foundation/nsregularexpression