{"id":10704,"date":"2020-07-07T12:42:46","date_gmt":"2020-07-07T12:42:46","guid":{"rendered":"https:\/\/fhug.org.uk\/kb\/?post_type=kb_article&#038;p=10704"},"modified":"2023-04-12T15:03:08","modified_gmt":"2023-04-12T15:03:08","slug":"understanding-lua-patterns","status":"publish","type":"kb_article","link":"https:\/\/www.fhug.org.uk\/kb\/kb-article\/understanding-lua-patterns\/","title":{"rendered":"Understanding Lua Patterns"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>A pattern is a formula for matching text strings that conform to some definable criteria (experienced coders need to remember Lua patterns are similar but not identical to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Regular_expression\">regular expressions<\/a>). Optionally, the pattern allows components of the string to be captured in order to compose a new text string incorporating those components.<\/p>\n<p>For example, the pattern\u00a0<code>ABC%d%d%d<\/code>\u00a0(where\u00a0<code>%d<\/code>\u00a0matches any digit) will match the letters\u00a0ABC\u00a0followed by any three digits, such as\u00a0ABC142\u00a0or\u00a0ABC897\u00a0or\u00a0ABC603, but will NOT match\u00a0ABC93X.<\/p>\n<p>So patterns comprise regular literal text characters that match themselves, such as\u00a0ABC\u00a0above, and\u00a0magic\u00a0or\u00a0meta\u00a0characters that have a special meaning, such as\u00a0<code>%d<\/code>\u00a0above. The following sections focus on the meanings of those\u00a0magic\u00a0characters.<\/p>\n<h2>Pattern Match Functions<\/h2>\n<p>Lua has some string functions that use patterns. Among them are:<\/p>\n<table style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td style=\"width: 25%;\">string.find(string, pattern)<\/td>\n<td style=\"width: 50%;\">finds the first instance of\u00a0pattern\u00a0in\u00a0string\u00a0and returns its position<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 25%;\">string.gmatch(string, pattern)<\/td>\n<td style=\"width: 50%;\">when called repeatedly, returns each successive instance of\u00a0pattern\u00a0in\u00a0string<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 25%;\">string.gsub(string, pattern, repl)<\/td>\n<td style=\"width: 50%;\">returns a string where all instances of\u00a0pattern\u00a0in\u00a0string\u00a0have been replaced with\u00a0repl<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 25%;\">string.match(string, pattern)<\/td>\n<td style=\"width: 50%;\">returns the first instance of\u00a0pattern\u00a0in\u00a0string<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Some of these functions have additional optional parameters, and behave slightly differently if the\u00a0pattern\u00a0defines\u00a0<a href=\"https:\/\/www.fhug.org.uk\/wiki\/doku.php?id=plugins:understanding_lua_patterns#captures\">Captures<\/a>. For details, see the Lua reference manual (online) for the version that you&#8217;re using (the links are in Useful External Links below).<\/p>\n<h2>Constructing a Pattern<\/h2>\n<p>So, how do we construct a pattern?<\/p>\n<p>At the foundation of patterns are\u00a0<a href=\"#charclasses\">Character Classes<\/a>\u00a0that represent sets of characters. Each character class matches just one character that conforms to that class. For example, the character class\u00a0<code>%d<\/code>\u00a0matches any one digit\u00a00-9, whereas the character class\u00a0<code>A<\/code>\u00a0matches the single letter\u00a0A.<\/p>\n<p>More complex structures are\u00a0<a href=\"#patternitems\">Pattern Items<\/a>\u00a0that represent combinations of characters. For example, the pattern item\u00a0<code>%d+<\/code>\u00a0matches a sequence of one or more digits, and\u00a0<code>A+<\/code>\u00a0matches a sequence of\u00a0A&#8217;s.<\/p>\n<p>Finally a\u00a0<a href=\"#pattern\">Pattern<\/a>\u00a0is a sequence of\u00a0<a href=\"#patternitems\">Pattern Items<\/a>\u00a0that may contain\u00a0<a href=\"#captures\">Captures<\/a>\u00a0of internal components whose purpose is explained later.<\/p>\n<p>Remember the\u00a0magic\u00a0characters\u00a0<code>% . [ ] ^ $ ( ) * + - ?<\/code>\u00a0have special contextual meanings, so usually don&#8217;t match themselves.<\/p>\n<h3><a id=\"charclasses\"><\/a>Character Classes<\/h3>\n<p style=\"text-align: left;\">Lua character classes are:<\/p>\n<table class=\" aligncenter\" style=\"border-collapse: collapse; width: 80%;\">\n<tbody>\n<tr>\n<td style=\"width: 8%;\"><strong>Class<\/strong><\/td>\n<td style=\"width: 50%;\"><strong>Meaning<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">Y<\/td>\n<td style=\"width: 50%;\">represents the character\u00a0Y\u00a0itself as long as it is not a\u00a0magic\u00a0character<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">.<\/td>\n<td style=\"width: 50%;\">represents any single character<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%a<\/td>\n<td style=\"width: 50%;\">represents all letters A-Z and a-z<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%c<\/td>\n<td style=\"width: 50%;\">represents all control characters such as Null, Tab, Carr.Return, Linefeed, Delete, etc<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%d<\/td>\n<td style=\"width: 50%;\">represents all digits 0-9<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%g<\/td>\n<td style=\"width: 50%;\">all printable characters except space (not Lua 5.1)<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%l<\/td>\n<td style=\"width: 50%;\">represents all lowercase letters a-z<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%p<\/td>\n<td style=\"width: 50%;\">represents all punctuation characters or symbols such as . , ? ! : ; @ [ ] _ { } ~<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%s<\/td>\n<td style=\"width: 50%;\">represents all white space characters such as Tab, Carr.Return, Linefeed, Space, etc<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%u<\/td>\n<td style=\"width: 50%;\">represents all uppercase letters A-Z<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%w<\/td>\n<td style=\"width: 50%;\">represents all alphanumeric characters A-Z and a-z and 0-9<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%x<\/td>\n<td style=\"width: 50%;\">represents all hexadecimal digits 0-9 and A-F and a-f<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%z<\/td>\n<td style=\"width: 50%;\">represents the character with code \\000 because embedded zeroes in a pattern do not work (<span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>6\/Lua 5.1)<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">\\0<\/td>\n<td style=\"width: 50%;\">represents the character with code \\000 because embedded zeroes in a pattern do not work (<span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>7\/Lua 5.3)<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\"><\/td>\n<td style=\"width: 50%;\">The upper case letter versions of the above reverses their meaning<br \/>\ni.e.\u00a0%A\u00a0represents all non-letters and\u00a0%D\u00a0represents all non-digits<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%Y<\/td>\n<td style=\"width: 50%;\">represents the character\u00a0Y\u00a0if it is any non-alphanumeric character<br \/>\nThis is the standard way to get a\u00a0magic\u00a0character to match itself<br \/>\nAny punctuation character (even a non\u00a0magic\u00a0one) preceded by a\u00a0%\u00a0represents itself<br \/>\ne.g.\u00a0%%\u00a0represents\u00a0%\u00a0percent and\u00a0%+\u00a0represents\u00a0+\u00a0plus<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">[set]<\/td>\n<td style=\"width: 50%;\">represents the class which is the union of all characters in the\u00a0set<br \/>\nA range of characters is specified by separating first and last character of range with a\u00a0&#8211;\u00a0hyphen e.g.\u00a01-5<br \/>\nAll classes described above may also be used as components in the\u00a0set<br \/>\ne.g.\u00a0[%w~]\u00a0(or\u00a0[~%w]) represents all alphanumeric characters plus the\u00a0~\u00a0tilde<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">[^set]<\/td>\n<td style=\"width: 50%;\">represents the complement of set, where set is interpreted as above<br \/>\ne.g.\u00a0[^A-Z]\u00a0represents any character except upper case letters<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Many patterns are simply made up of a sequence of these classes.<br \/>\nFor example, to match the string\u00a0### Abc\u00a0(where\u00a0#\u00a0designates a digit), you would use the pattern\u00a0<code>%d%d%d Abc<\/code>.<\/p>\n<p>Note: classes <code>%a<\/code> to <code>%x<\/code> and <code>%A<\/code> to <code>%X<\/code> above aren&#8217;t strictly necessary, being just shorthand for certain <code>[set]<\/code> or <code>[^set]<\/code> classes.<br \/>\ne.g.\u00a0<code>%a<\/code>\u00a0is\u00a0<code>[A-Za-z]<\/code>\u00a0,\u00a0<code>%d<\/code>\u00a0is\u00a0<code>[0-9]<\/code>\u00a0,\u00a0<code>%l<\/code>\u00a0is\u00a0<code>[a-z]<\/code>\u00a0,\u00a0<code>%L<\/code>\u00a0is\u00a0<code>[^a-z]<\/code>\u00a0,\u00a0<code>%U<\/code>\u00a0is\u00a0<code>[^A-Z]<\/code>\u00a0, and so on.<\/p>\n<h3><a id=\"patternitems\"><\/a>Pattern Items<\/h3>\n<p>By adding modifiers, you can extend the meaning of those <a href=\"#charclasses\">Character Classes<\/a> represented by class below.<\/p>\n<table class=\" aligncenter\" style=\"border-collapse: collapse; width: 80%;\">\n<tbody>\n<tr>\n<td style=\"width: 8%;\"><strong>Item<\/strong><\/td>\n<td style=\"width: 50%;\"><strong>Meaning<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">class<\/td>\n<td style=\"width: 50%;\">matches any single character in the\u00a0class<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">class*<\/td>\n<td style=\"width: 50%;\">matches 0 or more repetitions of\u00a0class\u00a0and will always match the longest possible chain<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">class+<\/td>\n<td style=\"width: 50%;\">matches 1 or more repetitions of\u00a0class\u00a0and will always match the longest possible chain<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">class-<\/td>\n<td style=\"width: 50%;\">matches 0 or more repetitions of\u00a0class\u00a0and will always match the shortest possible chain<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">class?<\/td>\n<td style=\"width: 50%;\">matches 0 or 1 occurrence of\u00a0class<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>For example,\u00a0<code>%d+<\/code>\u00a0will match a string of digits.<\/p>\n<p>There are also two special pattern items.<\/p>\n<table class=\" aligncenter\" style=\"border-collapse: collapse; width: 80%;\">\n<tbody>\n<tr>\n<td style=\"width: 8%;\"><strong>Item<\/strong><\/td>\n<td style=\"width: 50%;\"><strong>Meaning<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%N<\/td>\n<td style=\"width: 50%;\">for\u00a0N\u00a0between\u00a01\u00a0and\u00a09\u00a0matches the\u00a0Nth captured substring (see\u00a0<a href=\"#captures\">Captures\u00a0<\/a>below)<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">%bXY<\/td>\n<td style=\"width: 50%;\">matches a substring starting with\u00a0X\u00a0and ending with\u00a0Y\u00a0and the substring also has the same number of\u00a0X\u00a0as\u00a0Y<br \/>\nFor example,\u00a0<code>%b()<\/code>\u00a0will match balanced nested pairs of\u00a0( )\u00a0parentheses<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3><a id=\"pattern\"><\/a>Pattern<\/h3>\n<p>A Pattern is a sequence of Pattern Items that can be anchored to the start &amp;\/or end of a string.<\/p>\n<table class=\" aligncenter\" style=\"border-collapse: collapse; width: 80%;\">\n<tbody>\n<tr>\n<td style=\"width: 8%;\"><strong>Anchor<\/strong><\/td>\n<td style=\"width: 50%;\"><strong>Meaning<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">^<\/td>\n<td style=\"width: 50%;\">when at the beginning of a pattern, forces the pattern to match the start of a string<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\">$<\/td>\n<td style=\"width: 50%;\">when at the end of a pattern, forces the pattern to match the end of a string<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 8%;\"><\/td>\n<td style=\"width: 50%;\">When\u00a0^\u00a0or\u00a0$\u00a0is elsewhere in a pattern (except in\u00a0[^set]), it has no\u00a0magic\u00a0meaning and represents itself<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>For example,\u00a0<code>^A%d+Z$<\/code>\u00a0will match a string starting with\u00a0A, ending with\u00a0Z, with only digits in between.<\/p>\n<h3><a id=\"captures\"><\/a>Captures<\/h3>\n<p>A <a href=\"#pattern\">Pattern<\/a> may have sub-patterns enclosed by <code>( )<\/code> parentheses, that are counted as matches are found. They can be accessed using the <code>%N<\/code> item defined above. The empty capture <code>()<\/code> will return the string position where a match is found.<\/p>\n<p>For example,\u00a0<code>^A(%d+)Z$<\/code>\u00a0will capture just the digits from any matching string, and subsequently\u00a0<code>%1<\/code>\u00a0represents those captured digits.<\/p>\n<p>So the function\u00a0<code>string.gsub(S, \"^A(%d+)Z$\", \"%1\")<\/code>\u00a0will return just the digits from string\u00a0<code>S<\/code>\u00a0as long as it matches the pattern, otherwise it returns the original string\u00a0<code>S<\/code>\u00a0unaltered.<\/p>\n<h2>Examples<\/h2>\n<p>Here are a few basic examples of Lua Patterns that match Family Historian text.<\/p>\n<table style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td style=\"width: 50%;\"><strong>Lua Pattern<\/strong><\/td>\n<td style=\"width: 50%;\"><strong>Matching Text<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 25%;\">^Q[1-4] %d%d%d%d$<\/td>\n<td style=\"width: 50%;\">Quarter date e.g. Q2 1987 or Q4 1876<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 25%;\">^[123]?%d %u%l+ %d%d%d%d%$<\/td>\n<td style=\"width: 50%;\">Simple date e.g.\u00a021 March 1765\u00a0or\u00a08 June 1678<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 25%;\">^[1-3]?%d %u%l+ %d%d%d%d% %(%l%l%l%)$<\/td>\n<td style=\"width: 50%;\">Qualified date e.g.\u00a019 September 1765 (est)<br \/>\nNote how\u00a0magic\u00a0( )\u00a0parentheses need\u00a0%\u00a0prefix<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The following\u00a0<a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-code-snippets\/\">Code Snippets<\/a> use patterns, as does the <a href=\"https:\/\/pluginstore.family-historian.co.uk\/page\/plugin\/search-and-replace\">Search and Replace<\/a> plugin.<\/p>\n<ul>\n<li><a href=\"https:\/\/fhug.org.uk\/kb\/code-snippet\/split-a-filename-into-path-file-and-extension\/\">Split a Filename into Path, File, and Extension\u00a0<\/a><\/li>\n<li><a href=\"https:\/\/fhug.org.uk\/kb\/code-snippet\/split-a-string-into-numbers-using-separators\/\">Split a String into Numbers using Separators\u00a0<\/a><\/li>\n<li><a href=\"https:\/\/fhug.org.uk\/kb\/code-snippet\/plain-text-substitution\/\">Plain Text Substitution<\/a><\/li>\n<\/ul>\n<h2>Unicode UTF-8 Encoding<\/h2>\n<p>Note: In <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>6 and <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>7 the native <a href=\"https:\/\/www.lua.org\/manual\/5.3\/manual.html#6.5\">utf8<\/a> library is available (or can be implemented) to help in this area and can be supplemented with an additional <a href=\"https:\/\/gist.github.com\/Stepets\/3b4dbaf5e6e6a60f3862\">utf8 library<\/a> \u00a0to access extra functions; see <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules\/\">Lua references and Library Modules<\/a> for instructions how to include them. If you choose not to use these libraries, read on.<\/p>\n<p>Lua and its pattern matching is designed to work with\u00a0ANSI\u00a0encoded strings and does not recognise the special needs of multi-byte\u00a0UTF-8\u00a0encoding. Many of the\u00a0UTF-8\u00a0bytes are treated as members of the character classes described above with highly disruptive effects. So\u00a0UTF-8\u00a0compatible\u00a0ASCII\u00a0substitutes must be employed to avoid byte codes above\u00a0\\127.<\/p>\n<table style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td style=\"width: 20%;\">Class<\/td>\n<td style=\"width: 33.3333%;\">UTF-8 Replacement<\/td>\n<td style=\"width: 33.3333%;\">Description<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%a<\/td>\n<td style=\"width: 33.3333%;\">[A-Za-z]<\/td>\n<td style=\"width: 33.3333%;\">represents all unaccented letters<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%c<\/td>\n<td style=\"width: 33.3333%;\"><span lang=\"en-gb\"><span style=\"font-family: Arial; font-size: small;\">[%z\\001-\\031\\127]<\/span><\/span><span lang=\"en-gb\"><span style=\"font-family: Arial; font-size: small;\"> or<\/span><\/span><span lang=\"en-gb\"> <span style=\"font-family: Arial; font-size: small;\">[\\00<\/span><\/span><span lang=\"en-gb\"><span style=\"font-family: Arial; font-size: small;\">0<\/span><\/span><span lang=\"en-gb\"><span style=\"font-family: Arial; font-size: small;\">-\\031\\127]<\/span><\/span><\/td>\n<td style=\"width: 33.3333%;\">represents all control characters<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%d<\/td>\n<td style=\"width: 33.3333%;\">[0-9]<\/td>\n<td style=\"width: 33.3333%;\">represents all digits<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%l<\/td>\n<td style=\"width: 33.3333%;\">[a-z]<\/td>\n<td style=\"width: 33.3333%;\">represents all unaccented lowercase letters<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%p<\/td>\n<td style=\"width: 33.3333%;\">[!-\/:-@%[\\\\%]^_`{|}~]<\/td>\n<td style=\"width: 33.3333%;\">for all punctuation i.e. [\\033-\\047\\058-\\064\\091-\\096\\123-\\126]<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%s<\/td>\n<td style=\"width: 33.3333%;\">[\\t-\\r ]<\/td>\n<td style=\"width: 33.3333%;\">represents all white space characters i.e. [\\009-\\013\\032]<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%u<\/td>\n<td style=\"width: 33.3333%;\">[A-Z]<\/td>\n<td style=\"width: 33.3333%;\">represents all unaccented uppercase letters<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%w<\/td>\n<td style=\"width: 33.3333%;\">[A-Za-z0-9]<\/td>\n<td style=\"width: 33.3333%;\">represents all unaccented alphanumeric characters<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%x<\/td>\n<td style=\"width: 33.3333%;\">[0-9A-Fa-f]<\/td>\n<td style=\"width: 33.3333%;\">but\u00a0%x\u00a0is OK to represent all hexadecimal digits<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 20%;\">%z or \\0<\/td>\n<td style=\"width: 33.3333%;\"><\/td>\n<td style=\"width: 33.3333%;\">OK to represent the character with code \\000<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The inverse classes using capital letters need similar treatment and can be replaced by the ASCII versions above but with a leading <code>^<\/code> e.g. <code>%A<\/code> becomes <code>[^A-Za-z]<\/code> to represent all except unaccented letters. Note that none of the above techniques take account of UTF-8 accented letters or symbols, which being multi-byte codes, are difficult to define as patterns.<\/p>\n<p><code>(%W)<\/code>\u00a0is often used to detect non-alphanumerics to prefix with\u00a0<code>%<\/code>\u00a0to hide the\u00a0magic\u00a0pattern symbols, but can upset\u00a0UTF-8\u00a0text.\u00a0<code>([%^%$%(%)%%%.%[%]%*%+%-%?])\u00a0<\/code>is a safe\u00a0ASCII\u00a0substitute.<\/p>\n","protected":false},"template":"","fh_version":[14,15,739],"skill_level":[18,17],"topic":[73],"class_list":["post-10704","kb_article","type-kb_article","status-publish","hentry","fh_version-v5","fh_version-v6","fh_version-v7","skill_level-advanced","skill_level-intermediate","topic-writing-plugins"],"_links":{"self":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/kb_article\/10704","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/kb_article"}],"about":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/types\/kb_article"}],"wp:attachment":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/media?parent=10704"}],"wp:term":[{"taxonomy":"fh_version","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/fh_version?post=10704"},{"taxonomy":"skill_level","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/skill_level?post=10704"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/topic?post=10704"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}