RE2 regular expressions on streams? - regex

Is it possible to use Google RE2 with streams? Some input literals that we are suppose to process with regular expressions can potentially be too large to hold in-memory.

If there is a maximum match length, you could read the data in blocks of at least twice that length. If the match fails, or starts less than that many characters from the end, cut the current string, and append another block.
The length of the match string would never be more than the block length + max match length.
Example in C#:
public static IEnumerable<StreamMatch> MatchesInStream(
this Regex pattern, TextReader reader,
int maxMatchLength, int blockLength)
{
if (maxMatchLength <= 0)
{
throw new ArgumentException("Must be positive", "maxMatchLength");
}
if (blockLength < maxMatchLength)
{
throw new ArgumentException("Must be at least as long as maxMatchLength", "blockLength");
}
char[] buffer = new char[blockLength];
string chunk = "";
int matchOffset = 0;
// Read one block, and append to the string
int charsRead = reader.ReadBlock(buffer, 0, blockLength);
chunk += new string(buffer, 0, charsRead);
while (charsRead > 0 && chunk.Length > maxMatchLength)
{
int cutPosition = 0;
foreach (Match match in pattern.Matches(chunk))
{
if (match.Index > chunk.Length - maxMatchLength)
{
// The match could possibly have matched more characters.
// Read another block before trying again.
break;
}
yield return new StreamMatch(matchOffset, match);
cutPosition = match.Index + match.Length;
}
cutPosition = Math.Max(cutPosition, chunk.Length - maxMatchLength);
matchOffset += cutPosition;
chunk = chunk.Substring(cutPosition);
charsRead = reader.ReadBlock(buffer, 0, blockLength);
chunk += new string(buffer, 0, charsRead);
}
// Stream has ended. Try to match the last remaining characters.
foreach (Match match in pattern.Matches(chunk))
{
yield return new StreamMatch(matchOffset, match);
}
}
public class StreamMatch
{
public int MatchOffset { get; private set; }
public Match Match { get; private set; }
public StreamMatch(int matchOffset, Match match)
{
MatchOffset = matchOffset;
Match = match;
}
}
// One horrible XML parser
var reader = new StreamReader(stream);
var pattern = new Regex(#"<(/?)([\w:-]{1,15})([^<>]{0,50}(?<!/))(/?)>");
foreach (StreamMatch match in pattern.MatchesInStream(reader, 69, 128))
{
Console.WriteLine(match.Match.Value);
}

Related

How do you do this list operations in an efficient way in Dart (Bloc/Flutter)?

I have BLoC with the following state which contains 2 words ,
// 2 words are fixed and same length.
// in word_state.dart
abstract class WordState extends Equatable
const WordState(this.quest, this.answer, this.word, this.clicked);
final List<String> wordA; // WordA = ['B','A','L',L']
final List<String> wordB; // WordB = ['','','','']
#override
List<Object> get props => [wordA,wordB];
}
I want to ADD and REMOVE letters.
// in word_event.dart
class AddLetter extends WordEvent {
final int index;
const AddLetter(this.index);
}
class RemoveLetter extends WordEvent {
final int index;
const RemoveLetter(this.index);
}
1.ADD:
If I select the index of 'L' in wordA, then I add the letter 'L' in the first occurrence of '' (empty) in wordB.
// in word_bloc.dart
void _onLetterAdded(AddLetter event, Emitter<WordState> emit) {
final b = [...state.wordB];
b[b.indexOf('')] = state.wordA[event.index];
emit(WordLoaded(state.wordA, b));
}
//wordB, ['','','',''] into ['L','','','']
2.REMOVE:
If I deselect the index of 'L' in wordA, then I remove the last occurence of letter 'L' in wordB and shift the right side letters to left
void _onLetterRemoved(RemoveLetter event, Emitter<WordState> emit) {
final b = [...state.wordB];
final index = b.lastIndexOf(state.wordA[event.index]);
for (int i = index; i < 4 - 1; i++) {
b[i] = b[i + 1];
}
b[3] = '';
emit(WordLoaded(state.wordA, b));
}
}
// What i am trying to
// ['B','L','A','L']
// if index is 1 then ['B','A','L','']
This code is working fine, But I want to do the list operations in efficient way.
can you please check this code understand it and run it on dart pad.
List<String> wordA=['B','A','L','L'];
List<String> wordB=['','','',''];
List<String> wordBAll=['B','L','A','L'];
void main() {
wordB.insert(0,wordA[2]);
wordBAll.removeAt(wordBAll.length-1);
print(wordB);
print(wordBAll);
}

QML/C++ coloring every 8th character in a QString

I am making a converter to convert a string to binary and I want to change the color of every 8th character of the resulting binary conversion result to red to symbolize the beginning of each ascii character. The user enters a string a text input and the converted result is displayed in a text area like so:
Every 8th 0 or 1 should be red.
I'm not sure where to begin and is this even possible? And if I were to reverse the converter (user enters binary and its converted to ascii characters) could it still work? Thanks.
Edit:
I am adding "<font color='red'>" and "</font>" to the beginning and end of every eighth binary digit but the result displayed is literally "<font color='red'>0</font>", it is not applying the html styling.
My TextInput sets the TextArea.text whenever the user types using a C++ function.
TextInput {
...
onTextChanged: {
uiText.setBinaryString(myTextInput.text)
myTextAreaText.text = uiText.getBinaryString()
}
}
C++ functions
void UITextConnector::setBinaryString(QString s)
{
binaryString = convertToBinary(s);
}
QString UITextConnector::getBinaryString()
{
return binaryString;
}
QString UITextConnector::convertToBinary(QString qs)
{
std::string resultString;
if (binaryMode) {
std::string qStringConverted = qs.toStdString();
for (std::size_t i = 0; i < qStringConverted.size(); i++) {
std::bitset<8> b(qStringConverted.c_str()[i]);
std::string nextBinary = b.to_string();
nextBinary = "<font color='#00AA00'>" + nextBinary.substr(0,1) + "</font>" + nextBinary.substr(1);
resultString += nextBinary;
}
} else {
std::string qStringConverted = qs.toStdString();
for (std::size_t i = 0; i < qStringConverted.size() ; i = i + 8) {
resultString += UITextConnector::strToChar(qStringConverted.substr(i, i+8).c_str());
}
}
return QString::fromStdString(resultString);
}
However, this only works if I use a label but not when I use a textArea.
Since you didn't provide any source or whatever it is too difficult to understand what is your fail. Anyway, I would do that in the following way:
TextArea {
id: txt
anchors.fill: parent
anchors.margins: 10
textFormat: TextEdit.RichText
text: ""
function setText(str)
{
var arr = str.match(/.{1,8}/g) || [];
var result = "";
for(var index in arr)
{
result += "<font color='red'>" + arr[index].substring(0, 1) + "</font>" + arr[index].substring(1);
}
txt.text = result;
}
Component.onCompleted: {
txt.setText("aaaaaaaabbbbbbbbccccccccdddd");
}
}

Replacing dynamic variable in string UNITY

I am making a simple dialogue system, and would like to "dynamise" some of the sentences.
For exemple, I have a Sentence
Hey Adventurer {{PlayerName}} !
Welcome in the world !
Now In code I am trying to replace that by the real value of the string in my game. I am doing something like this. But it doesn't work. I do have a string PlayerName in my component where the function is situated
Regex regex = new Regex("(?<={{)(.*?)(?=}})");
MatchCollection matches = regex.Matches(sentence);
for(int i = 0; i < matches.Count; i++)
{
Debug.Log(matches[i]);
sentence.Replace("{{"+matches[i]+"}}", this.GetType().GetField(matches[i].ToString()).GetValue(this) as string);
}
return sentence;
But this return me an error, even tho the match is correct.
Any idea of a way to do fix, or do it better?
Here's how I would solve this.
Create a dictionary with keys as the values you wish to replace and values as what you will be replacing them to.
Dictionary<string, string> valuesToReplace;
valuesToReplace = new Dictionary<string, string>();
valuesToReplace.Add("[playerName]", "Max");
valuesToReplace.Add("[day]", "Thursday");
Then check the text for the values in your dictionary.
If you make sure all of your keys start with "[" and end with "]" this will be quick and easy.
List<string> replacements = new List<string>();
//We will save all of the replacements we are about to perform here.
//This is done so we won't be modifying the original string while working on it, which will create problems.
//We will save them in the following format: originalText}newText
for(int i = 0; i < text.Length; i++) //Let's loop through the entire text
{
int startOfVar = 9999;
if(text[i] == '[') //We have found the beginning of a variable
{
startOfVar = i;
}
if(text[i] == ']') //We have found the ending of a variable
{
string replacement = text.Substring(startOfVar, i - startOfVar); //We have found the section we wish to replace
if (valuesToReplace.ContainsKey(replacement))
replacements.Add(replacement + "}" + valuesToReplace[replacement]); //Add the replacement we are about to perform to our dictionary
}
}
//Now let's perform the replacements:
foreach(string replacement in replacements)
{
text = text.Replace(replacement.Split('}')[0], replacement.Split('}')[1]); //We split our line. Remember the old value was on the left of the } and the new value was on the right
}
This will also work much faster, since it allows you to add as many variables as you wish without making the code slower.
Using Regex.Replace method, and a MatchEvaluator delegate (untested):
Dictionary<string, string> Replacements = new Dictionary<string, string>();
Regex DialogVariableRegex = new Regex("(?<={{)(.*?)(?=}})");
string Replace(string sentence) {
DialogVariableRegex.Replace(sentence, EvaluateMatch);
return sentence;
}
string EvaluateMatch(Match match) {
var matchedKey = match.Value;
if (Replacements.ContainsKey(matchedKey))
return Replacements[matchedKey];
else
return ">>MISSING KEY<<";
}
This is kind of old now, but I figured I'd update the accepted code above. It won't work since the start index is reset every time the loop iterates, so setting startOfVar = i gets completely reset by the time it hits the closing character. Plus there are problems if there's an open bracket '[' and no closing one. You can also no longer use those brackets in your text.
There's also setting the splitter to a single character. It tests fine, but if I set my player name to "Rob}ert", that will cause problems when it performs the replacements.
Here is my updated take on the code which I've tested works in Unity:
public string EvaluateVariables(string str)
{
Dictionary<string, string> varDict = GetVariableDictionary();
List<string> varReplacements = new List<string>();
string matchGuid = Guid.NewGuid().ToString();
bool matched = false;
int start = int.MaxValue;
for (int i = 0; i < str.Length; i++)
{
if (str[i] == '{')
{
if (str[i + 1] == '$')
{
start = i;
matched = true;
}
}
else if (str[i] == '}' && matched)
{
string replacement = str.Substring(start, (i - start) + 1);
if (varDict.ContainsKey(replacement))
{
varReplacements.Add(replacement + matchGuid + varDict[replacement]);
}
start = int.MaxValue;
matched = false;
}
}
foreach (string replacement in varReplacements)
{
str = str.Replace(replacement.Split(new string[] { matchGuid }, StringSplitOptions.None)[0], replacement.Split(new string[] { matchGuid }, StringSplitOptions.None)[1]);
}
return str;
}
private Dictionary<string, string> GetVariableDictionary()
{
Dictionary<string, string> varDict = new Dictionary<string, string>();
varDict.Add("{$playerName}", playerName);
varDict.Add("{$npcName}", npcName);
return varDict;
}

Hive regex for extracting keywords from url

Filenames are following :
file:///storage/emulated/0/SHAREit/videos/Dangerous_Hero_(2017)____Latest_South_Indian_Full_Hindi_Dubbed_Movie___2017_.mp4
file:///storage/emulated/0/VidMate/download/%E0%A0_-_Promo_Songs_-_Khiladi_-_Khesari_Lal_-_Bho.mp4
file:///storage/emulated/0/WhatsApp/Media/WhatsApp%20Video/VID-20171222-WA0015.mp4
file:///storage/emulated/0/bluetooth/%5DChitaChola%7B%7D%D8%B9%D8%A7%D9%85%D8%B1%24%20.3gp
I want to write hive regex to extract words from each string.
for example in 1st string output should be : storage,emulated,....
UPDATE
This Code gives me result , but i wanted regex instead of below code.
package uri_keyword_extractor;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
import java.util.ArrayList;
public class UDFUrlKeywordExtractor extends UDF {
private Text result = new Text();
public Text evaluate(Text url) {
if (url == null) {
return null;
}
String keywords = url_keyword_maker(url.toString());
result.set(keywords);
return result;
}
private static String url_keyword_maker(String url) {
// TODO Auto-generated method stub
ArrayList<String> keywordAr = new ArrayList<String>();
char[] charAr = url.toCharArray();
for (int i = 0; i < charAr.length; i++) {
int current_index = i;
// check if character is a-z or A-Z
char ch = charAr[i];
StringBuilder sb = new StringBuilder();
while (current_index < charAr.length-1 && isChar(ch)) {
sb.append(ch);
current_index = current_index+1;
ch = charAr[current_index];
}
String word = sb.toString();
if (word.length() >= 2) {
keywordAr.add(word);
}
i = current_index;
}
//
StringBuilder sb = new StringBuilder();
for(int i =0; i < keywordAr.size();i++) {
String current = keywordAr.get(i);
sb.append(current);
if(i < keywordAr.size() -1) {
sb.append(",");
}
}
return sb.toString();
}
private static boolean isChar(char ch) {
// TODO Auto-generated method stub
int ascii_value = (int) ch;
// A-Z => (65,90) a-z => (97,122)
// condition 1 : A-Z , condition 2 : a-z character check
if ( (ascii_value >= 65 && ascii_value <= 90) || (ascii_value >= 97 && ascii_value <= 122) ) {
return true;
} else {
return false;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String test1 = "file:///storage/emulated/0/SHAREit/videos/Dangerous_Hero_(2017)____Latest_South_Indian_Full_Hindi_Dubbed_Movie___2017_.mp4";
String test2 = "file:///storage/emulated/0/VidMate/download/%E0%A0_-_Promo_Songs_-_Khiladi_-_Khesari_Lal_-_Bho.mp4";
String test3 = "file:///storage/emulated/0/bluetooth/%5DChitaChola%7B%7D%D8%B9%D8%A7%D9%85%D8%B1%24%20.3gp";
System.out.println(url_keyword_maker(test1).toString());
System.out.println(url_keyword_maker(test2).toString());
System.out.println(url_keyword_maker(test3).toString());
}
}
Use split(str, regex_pattern) function, it splits str using regex as delimiter pattern and returns array. Then use lateral view + epxlode to explode array and filter keywords by length as in your Java code. Then apply collect_set to re-assemble array of keywords+concat_ws(delimeter, str) function to convert array to the delimited string if necessary.
The regex I passed to the split function is '[^a-zA-Z]'.
Demo:
select url_nbr, concat_ws(',',collect_set(key_word)) keywords from
(--your URLs example, url_nbr here is just for reference
select 'file:///storage/emulated/0/SHAREit/videos/Dangerous_Hero_(2017)____Latest_South_Indian_Full_Hindi_Dubbed_Movie___2017_.mp4' as url, 1 as url_nbr union all
select 'file:///storage/emulated/0/VidMate/download/%E0%A0_-_Promo_Songs_-_Khiladi_-_Khesari_Lal_-_Bho.mp4' as url, 2 as url_nbr union all
select 'file:///storage/emulated/0/WhatsApp/Media/WhatsApp%20Video/VID-20171222-WA0015.mp4' as url, 3 as url_nbr union all
select 'file:///storage/emulated/0/bluetooth/%5DChitaChola%7B%7D%D8%B9%D8%A7%D9%85%D8%B1%24%20.3gp' as url, 4 as url_nbr)s
lateral view explode(split(url, '[^a-zA-Z]')) v as key_word
where length(key_word)>=2 --filter here
group by url_nbr
;
Output:
OK
1 file,storage,emulated,SHAREit,videos,Dangerous,Hero,Latest,South,Indian,Full,Hindi,Dubbed,Movie,mp
2 file,storage,emulated,VidMate,download,Promo,Songs,Khiladi,Khesari,Lal,Bho,mp
3 file,storage,emulated,WhatsApp,Media,Video,VID,WA,mp
4 file,storage,emulated,bluetooth,DChitaChola,gp
Time taken: 37.767 seconds, Fetched: 4 row(s)
Maybe I have missed something from your java code, but hope you have caught the idea, so you can easily modify my code and add additional processing if necessary.

extract domain between two words

I have in a log file some lines like this:
11-test.domain1.com Logged ...
37-user1.users.domain2.org Logged ...
48-me.server.domain3.net Logged ...
How can I extract each domain without the subdomains? Something between "-" and "Logged".
I have the following code in c++ (linux) but it doesn't extract well. Some function which is returning the extracted string would be great if you have some example of course.
regex_t preg;
regmatch_t mtch[1];
size_t rm, nmatch;
char tempstr[1024] = "";
int start;
rm=regcomp(&preg, "-[^<]+Logged", REG_EXTENDED);
nmatch = 1;
while(regexec(&preg, buffer+start, nmatch, mtch, 0)==0) /* Found a match */
{
strncpy(host, buffer+start+mtch[0].rm_so+3, mtch[0].rm_eo-mtch[0].rm_so-7);
printf("%s\n", tempstr);
start +=mtch[0].rm_eo;
memset(host, '\0', strlen(host));
}
regfree(&preg);
Thank you!
P.S. no, I cannot use perl for this because this part is inside of a larger c program which was made by someone else.
EDIT:
I replace the code with this one:
const char *p1 = strstr(buffer, "-")+1;
const char *p2 = strstr(p1, " Logged");
size_t len = p2-p1;
char *res = (char*)malloc(sizeof(char)*(len+1));
strncpy(res, p1, len);
res[len] = '\0';
which is extracting very good the whole domain including subdomains.
How can I extract just the domain.com or domain.net from abc.def.domain.com ?
is strtok a good option and how can I calculate which is the last dot ?
#include <vector>
#include <string>
#include <boost/regex.hpp>
int main()
{
boost::regex re(".+-(?<domain>.+)\\s*Logged");
std::string examples[] =
{
"11-test.domain1.com Logged ...",
"37-user1.users.domain2.org Logged ..."
};
std::vector<std::string> vec(examples, examples + sizeof(examples) / sizeof(*examples));
std::for_each(vec.begin(), vec.end(), [&re](const std::string& s)
{
boost::smatch match;
if (boost::regex_search(s, match, re))
{
std::cout << match["domain"] << std::endl;
}
});
}
http://liveworkspace.org/code/1983494e6e9e884b7e539690ebf98eb5
something like this with boost::regex. Don't know about pcre.
Is the in a standard format?
it appears so, is there a split function?
Edit:
Here is some logic.
Iterate through each domain to be parsed
Find a function to locate the index of the first string "-"
Next find the index of the second string minus the first string "Logged"
Now you have the full domain.
Once you have the full domain "Split" the domain into your object of choice (I used an array)
now that you have the array broken apart locate the index of the value you wish to reassemble (concatenate) to capture only the domain.
NOTE Written in C#
Main method which defines the first value and the second value
`static void Main(string[] args)
{
string firstValue ="-";
string secondValue = "Logged";
List domains = new List { "11-test.domain1.com Logged", "37-user1.users.domain2.org Logged","48-me.server.domain3.net Logged"};
foreach (string dns in domains)
{
Debug.WriteLine(Utility.GetStringBetweenFirstAndSecond(dns, firstValue, secondValue));
}
}
`
Method to parse the string:
`public string GetStringBetweenFirstAndSecond(string str, string firstStringToFind, string secondStringToFind)
{
string domain = string.Empty;
if(string.IsNullOrEmpty(str))
{
//throw an exception, return gracefully, whatever you determine
}
else
{
//This can all be done in one line, but I broke it apart so it can be better understood.
//returns the first occurrance.
//int start = str.IndexOf(firstStringToFind) + 1;
//int end = str.IndexOf(secondStringToFind);
//domain = str.Substring(start, end - start);
//i.e. Definitely not quite as legible, but doesn't create object unnecessarily
domain = str.Substring((str.IndexOf(firstStringToFind) + 1), str.IndexOf(secondStringToFind) - (str.IndexOf(firstStringToFind) + 1));
string[] dArray = domain.Split('.');
if (dArray.Length > 0)
{
if (dArray.Length > 2)
{
domain = string.Format("{0}.{1}", dArray[dArray.Length - 2], dArray[dArray.Length - 1]);
}
}
}
return domain;
}
`