I have a predefined code, e.g."12-345-6789", and wish to match the first and last portions with Lua patterns, e.g. "12-6789". An exclusion of the second number set and the hyphen should work but I am having trouble figuring that out with patterns or if it is possible.
I know I could capture each individually like so
code = "12-345-6789"
first, middle, last = string.match(code, "(%d+)-(%d+)-(%d+)")
and use that but it would require a lot of code rewriting on my part. I would ideally like to take the current table of pattern matches and add it to be used with string.match
lcPart = { "^(%d+)", "^(%d+%-%d+)", "(%d+)$", ?new pattern here? }
code = "12-345-6789"
newCode = string.match(code, lcPart[4])
You can't do this with one capture, but it's trivial to splice the results of two captures together:
local first, last = string.match(code, "(%d+)%-%d+%-(%d+)")
local newid = first .. "-" .. last
If you're trying to match against a list of patterns, it may be better to refactor it into a list of functions instead:
local matchers = {
function(s) return string.match(s, "^(%d+)") end,
function(s) return string.match(s, "^(%d+%-%d+)") end,
-- ...
function(s)
local first, last = string.match(code, "(%d+)%-%d+%-(%d+)")
return first .. "-" .. last
end,
}
for _,matcher in ipairs(matcher) do
local match = matcher(code)
if match then
-- do something
end
end
I know this is an old thread, but someone might still find this useful.
If you need only the first and last sets of digits, separated by a hyphen you could use string.gsub for that
local code = "12-345-6789"
local result = string.gsub(code, "(%d+)%-%d+%-(%d+)", "%1-%2")
This will simply return the string "12-6789" by using the first and second captures from the pattern.
Related
I'm trying to implement in a different way what I can already do implementing some custom matlab functions. Let us suppose to have this string 'AAAAAAAAAAAaaaaaaaaaaaTTTTTTTTTTTTTTTTsssssssssssTTTTTTTTTT' I know to remove each lowercase sub strings with
regexprep(String, '[a-z]*', '')
But since I want to understand how to take indexes of these substrings and using them to check them and remove them maybe with a for loop I'm investigating about how to do it.
Regexp give the indexes :
[Start,End] = regexp(Seq,'[a-z]{1,}');
but i'm not succeeding in figuring out how to use them to check these sequences and eliminate them.
With the indexing approach you get several start and end indices (two in your example), so you need a loop to remove the corresponding sections from the string. You should remove them from last to first, otherwise indices that haven't been used yet will become invalid as you remove sections:
x = 'AAAAAAAAAAAaaaaaaaaaaaTTTTTTTTTTTTTTTTsssssssssssTTTTTTTTTT'; % input
y = x; % initiallize result
[Start, End] = regexp(x, '[a-z]{1,}');
for k = numel(Start):-1:1 % note: from last to first
y(Start(k):End(k)) = []; % remove section
end
I'm trying to use pyparsing to build a parser that will match on all text within an arbitrarily nested set of brackets. If we consider a string like this:
"[A,[B,C],[D,E,F],G] Random Middle text [H,I,J]"
What I would like is for a parser to match in a way that it returns two matches:
[
"[A,[B,C],[D,E,F],G]",
"[H,I,J]"
]
I was able to accomplish a somewhat-working version of this using a barrage of originalTextFor mashed up with nestedExpr, but this breaks when your nesting is deeper than the number of OriginalTextFor expressions.
Is there a straightforward way to only match on the outermost expression grabbed by nestedExpr, or a way to modify its logic so that everything after the first paired match is treated as plaintext rather than being parsed?
update: One thing that seems to come close to what I want to accomplish is this modified version of the logic from nestedExpr:
def mynest(opener='{', closer='}'):
content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS))
ret = Forward()
ret <<= ( Suppress(opener) + originalTextFor(ZeroOrMore( ret | content )) + Suppress(closer) )
return ret
This gets me most of the way there, although there's an extra level of list wrapping in there that I really don't need, and what I'd really like is for those brackets to be included in the string (without getting into an infinite recursion situation by not suppressing them).
parser = mynest("[","]")
result = parser.searchString("[A,[B,C],[D,E,F],G] Random Middle text [H,I,J]")
result.asList()
>>> [['A,[B,C],[D,E,F],G'], ['H,I,J']]
I know I could strip these out with a simple list comprehension, but it would be ideal if I could just eliminate that second, redundant level.
Not sure why this wouldn't work:
sample = "[A,[B,C],[D,E,F],G] Random Middle text [H,I,J]"
scanner = originalTextFor(nestedExpr('[',']'))
for match in scanner.searchString(sample):
print(match[0])
prints:
'[A,[B,C],[D,E,F],G]'
'[H,I,J]'
What is the situation where "this breaks when your nesting is deeper than the number of OriginalTextFor expressions"?
I have a problem with splitting string into two parts on special character.
For example:
12345#data
or
1234567#data
I have 5-7 characters in first part separated with "#" from second part, where are another data (characters,numbers, doesn't matter what)
I need to store two parts on each side of # in two variables:
x = 12345
y = data
without "#" character.
I was looking for some Lua string function like splitOn("#") or substring until character, but I haven't found that.
Use string.match and captures.
Try this:
s = "12345#data"
a,b = s:match("(.+)#(.+)")
print(a,b)
See this documentation:
First of all, although Lua does not have a split function is its standard library, it does have string.gmatch, which can be used instead of a split function in many cases. Unlike a split function, string.gmatch takes a pattern to match the non-delimiter text, instead of the delimiters themselves
It is easily achievable with the help of a negated character class with string.gmatch:
local example = "12345#data"
for i in string.gmatch(example, "[^#]+") do
print(i)
end
See IDEONE demo
The [^#]+ pattern matches one or more characters other than # (so, it "splits" a string with 1 character).
Problem: From TrajCompact, i find all the prefix and the value after prefix, using regexp, with this code:
[digits{1:2}] = ndgrid(0:4);
for k=1:25
matches(:,k)=regexp(TrajCompact(:,1),sprintf('%d%d.*',digits{1}(k),digits{2}(k)),'match','once');
end
I want only the postfix of matches, how can delete the prefix from matches?
Method using regular expressions
You can put the .* section in a group by enclosing it in parenthesis (i.e. (.*)). Matlab has some peculiar 'token' nomenclature for this. In any case, an example of how it works:
[match, group] = regexp('25blah',sprintf('%d%d(.*)',2,5),'match','once','tokens');
Then:
match would be a char array containing '25blah'
group would be a 1x1 cell array containing the string 'blah'.
That is, the variable group would hold what you're looking for.
Hack method
Since your prefix is always two digits, you could also just take everything from the 3rd character of the match onwards:
my_string = match(3:end);
other comments
You may want to require the prefix to occur at the beginning of the string by adding ^ to the beginning of your regular expression. Eg., make the line:
[match, group] = regexp('25blah',sprintf('^%d%d(.*)',2,5),'match','once','tokens');
As it is, your current regular expression would match strings like zzzzzzzzz25stuff. I'm not sure if you want that (assuming it can occur in your data).
How do I remove lines from a string begins with another string in Lua ? For instance i want to remove all line from string result begins with the word <Table. This is the code I've written so far:
for line in result:gmatch"<Table [^\n]*" do line = "" end
string.gmtach is used to get all occurrences of a pattern. For replacing certain pattern, you need to use string.gsub.
Another problem is your pattern <Table [^\n]* will match all line containing the word <Table, not just begins with it.
Lua pattern doesn't support beginning of line anchor, this almost works:
local str = result:gsub("\n<Table [^\n]*", "")
except that it will miss on the first line. My solution is using a second run to test the first line:
local str1 = result:gsub("\n<Table [^\n]*", "")
local str2 = str1:gsub("^<Table [^\n]*\n", "")
The LPEG library is perfect
for this kind of task.
Just write a function to create custom line strippers:
local mk_striplines
do
local lpeg = require "lpeg"
local P = lpeg.P
local Cs = lpeg.Cs
local lpegmatch = lpeg.match
local eol = P"\n\r" + P"\r\n" + P"\n" + P"\t"
local eof = P(-1)
local linerest = (1 - eol)^1 * (eol + eof) + eol
mk_striplines = function (pat)
pat = P (pat)
local matchline = pat * linerest
local striplines = Cs (((matchline / "") + linerest)^1)
return function (str)
return lpegmatch (striplines, str)
end
end
end
Note that the argument to mk_striplines() may be a string or a
pattern.
Thus the result is very flexible:
mk_striplines (P"<Table" + P"</Table>") would create a stripper
that drops lines with two different patterns.
mk_striplines (P"x" * P"y"^0) drops each line starting with an
x followed by any number of y’s -- you get the idea.
Usage example:
local linestripper = mk_striplines "foo"
local test = [[
foo lorem ipsum
bar baz
buzz
foo bar
xyzzy
]]
print (linestripper (test))
The other answers provide good solutions to actually stripping lines from a string, but don't address why your code is failing to do that.
Reformatting for clarity, you wrote:
for line in result:gmatch"<Table [^\n]*" do
line = ""
end
The first part is a reasonable way to iterate over result and extract all spans of text that begin with <Table and continue up to but not including the next newline character. The iterator returned by gmatch returns a copy of the matching text on each call, and the local variable line holds that copy for the body of the for loop.
Since the matching text is copied to line, changes made to line are not and cannot modifying the actual text stored in result.
This is due to a more fundamental property of Lua strings. All strings in Lua are immutable. Once stored, they cannot be changed. Variables holding strings are actually holding a pointer into the internal table of reference counted immutable strings, which permits only two operations: internalization of a new string, and deletion of an internalized string with no remaining references.
So any approach to editing the content of the string stored in result is going to require the creation of an entirely new string. Where string.gmatch provides an iteration over the content but cannot allow it to be changed, string.gsub provides for creation of a new string where all text matching a pattern has been replaced by something new. But even string.gsub is not changing the immutable source text; it is creating a new immutable string that is a copy of the old with substitutions made.
Using gsub could be as simple as this:
result = result:gsub("<Table [^\n]*", "")
but that will disclose other defects in the pattern itself. First, and most obviously, nothing requires that the pattern match at only the beginning of the line. Second, the pattern does not include the newline, so it will leave the line present but empty.
All of that can be refined by careful and clever use of the pattern library. But it doesn't change the fact that you are starting with XML text and are not handling it with XML aware tools. In that case, any approach based on pattern matching or even regular expressions is likely to end in tears.
result = result:gsub('%f[^\n%z]<Table [^\n]*', '')
The start of this pattern, '%f[^\n%z], is a frontier pattern which will match any transition from either a newline or zero character to another character, and for frontier patterns the pre-first character counts as a zero character. In other words, using that prefix allows the rest of the pattern to match at either the first line or any other start-of-line.
Reference: the Lua 5.3 manual, section 6.4.1 on string patterns