Apps Script findText() for Google Docs - regex

I'm applying RegEx search to a Google Document text with some markdown code block ticks (```). Running the code below on my doc is returning a null result.
var codeBlockRegEx = '`{3}((?:.*?\s?)*?)`{3}'; // RegEx to find (lazily) all text between triple tick marks (/`/`/`), inclusive of whitespace such as carriage returns, tabs, newlines, etc.
var reWithCodeBlock = body.findText(codeBlockRegEx); // reWithCodeBlock evaluates to 'null'
I suspect that there's some element of regex in my code that is not supported by RE2, but the documentation has not shed light on this. Any ideas?

I received null as well- I was able to get the below to work using 3 ` surrounding the word test within a paragraph.
I did find this information:
findText method of objects of class Text in Apps Script, extending Google Docs. Documentation says “A subset of the JavaScript regular expression features are not fully supported, such as capture groups and mode modifiers.” In particular, it does not support lookarounds.
function findXtext() {
var body = DocumentApp.getActiveDocument().getBody();
var foundElement = body.findText("`{3}(test)`{3}");
while (foundElement != null) {
// Get the text object from the element
var foundText = foundElement.getElement().asText();
// Where in the element is the found text?
var start = foundElement.getStartOffset();
var end = foundElement.getEndOffsetInclusive();
// Set Bold
foundText.setBold(start, end, true);
// Change the background color to yellow
foundText.setBackgroundColor(start, end, "#FCFC00");
// Find the next match
foundElement = body.findText("`{3}(test)`{3}", foundElement);
}
}

Related

Extract JSON from String using flutter dart

Hello I want to extract JSON from below input string.
I have tried bellow regex in java and it is working fine,
private static final Pattern shortcode_media = Pattern.compile("\"shortcode_media\":(\\{.+\\})");
I want in regex for dart.
Input String
<script type="text/javascript">window.__initialDataLoaded(window._sharedData);</script><script type="text/javascript">window.__additionalDataLoaded('/p/B9fphP5gBeG/',{"graphql":{"shortcode_media":{"__typename":"GraphSidecar","id":"2260708142683789190","shortcode":"B9fphP5gBeG","dimensions":{"height":1326,"width":1080}}}});</script><script type="text/javascript">
<script type="text/javascript">window.__initialDataLoaded(window._newData);</script><script type="text/javascript">window._newData('/p/B9fphP5gBeG/',{"graphql":{"post":{"__typename":"id","id":"2260708142683789190","new_code":"B9fphP5gBeG"}}});</script><script type="text/javascript">
(function(){
function normalizeError(err) {
var errorInfo = err.error || {};
var getConfigProp = function(propName, defaultValueIfNotTruthy) {
var propValue = window._sharedData && window._sharedData[propName];
return propValue ? propValue : defaultValueIfNotTruthy;
};
return {}
}
)
Expected json
{"graphql":{"shortcode_media":{"__typename":"GraphSidecar","id":"2260708142683789190","shortcode":"B9fphP5gBeG","dimensions":{"height":1326,"width":1080}}}}
Note: There are multiple json string in input string, i need json of shortcode_media tag
please use
void main() {
​
String json = '''
{"graphql":
{"shortcode_media":{"__typename":"GraphSidecar","id":"2260708142683789190","shortcode":"B9fphP5gBeG","dimensions":{"height":1326,"width":1080}}},
"abc":{"def":"test"}
}
''';
RegExp regExp = new RegExp(
"\"shortcode_media\":(\\{.+\\})",
caseSensitive: false,
multiLine: false,
);
print(regExp.stringMatch(json).toString());
}
output
"shortcode_media":{"__typename":"GraphSidecar","id":"2260708142683789190","shortcode":"B9fphP5gBeG","dimensions":{"height":1326,"width":1080}}}
Dartpad
The corresponding Dart RegExp would be:
static final RegExp shortcodeMedia = RegExp(r'"shortcode_media":(\{.+\})");
It does not work, though. JSON is not a regular language, so you can't parse it using regular expressions.
The value of "shortcode_media" in your example JSON ends with several } characters. The RegExp will stop the match at the third of those, even though the second } is the one matching the leading {. If your JSON text contains any further values after the shortcode_media entry, those might be included as well.
Stopping at the first } would also be too short.
If someone reorders the JSON source code to the equivalent
"shortcode_media":{"dimensions":{"height":1326,"width":1080},"__typename":"GraphSidecar","id":"2260708142683789190","shortcode":"B9fphP5gBeG"}
(that is, putting the "dimensions" entry first), then you would only capture until the end of the dimensions block.
I would recommend either using a proper JSON parser, or at least improving the RegExp to be able to handle a single nested JSON object - since you seem to already know that it will happen.
Such a RegExp could be:
RegExp(r'"shortcode_media":(\{(?:[^{}]*(?:\{.*?\})?)*?\})')
This RegExp will capture the correct number of braces for the example code, but still won't work if there are more nested JSON objects. Only a real parser can handle the general case correctly.

Regex for getting content of a html property when another specific property doesn't exist

I struggle to find a solution for what is probably pretty simple, and despite I crawl a lot of questions, I can't manage to make it work.
Here are 2 HTML elements:
Test1
Test2
I want to get ONLY the content of the 1st element's href property (#content1). It must match because the html element contains no "onclick" property.
This regex works for matching the 1st element only:
^<a href="#"((?!onclick).)*$
but I can't figure out how to get the HREF content.
I've tried this:
^<a href="#(.*)"((?!onclick).)*$
but in this case, both elements are matching.
Thanks for your help !
I strongly suggest that you should do that in two steps. For one thing, parsing arbitrary html with a regexp is a notoriously slippery and winding road. For the other: there is no achievement in doing everything with one illegible regex.
And there's more to it: "contains no "onclick" attribute" is not the same as "href attribute is not directly followed by onclick attribute". So, a one-regex-solution would be either very complicated or very fragile (html tags have arbitrary attributes order).
var a = [
'Test1',
'Test2'
];
console.log(
a.filter(i => i.match(/onclick/i) == null)
.map(i => i.match(/href="([^"]+)"/i)[1]
)
This assumes that your href attribute values are valid and do not contain quotes (which is, of course, technically possible).
Regex is not made for this. JavaScript would work better. This code will store an array of the hrefs matching your requirements in the variable hrefArray.
var hrefArray = [];
for (var elem of document.getElementsByTagName('a')) {
if (elem.onclick) hrefArray.push(elem.href)
}
An example with your HTML is in the snippet below:
var hrefArray = [];
for (var elem of document.getElementsByTagName('a')) {
if (elem.onclick) hrefArray.push(elem.href)
}
console.log(hrefArray);
body {
background-color: gray;
}
Test1
Test2

Google App Script findText regex not working for new line character

I'm trying to locate/modify text in my Google Document where the text has been broken across a full line break. My regular expression below works when I manually find text in the Google document (CTRL+F) and then search via the regular expression dialog. What is baffling is why the exact same regex doesn't work in the code below on full line breaks, i.e. "\n" (note: the soft line "\v" breaks are ok).
The second approach finds the text but I'm unable to do anything with it as I need the element object in-order to manipulate the text.
//Test document 1Q6v8ipqA81LoPtpk71NdqTaIEqMjki1KIJbrm0bILBg contains the following text:
//
//This Agreement shall not be assigned by either party without the prior\n
//written consent of the parties hereto
var doc = DocumentApp.openById('1Q6v8ipqA81LoPtpk71NdqTaIEqMjki1KIJbrm0bILBg');
//Method 1 - does NOT locate the text
var body = doc.getBody();
var pattern = "prior[\s]*written";
var foundElement = body.findText(pattern);
while (foundElement != null) {
var foundText = foundElement.getElement().asText();
var start = foundElement.getStartOffset();
var end = foundElement.getEndOffsetInclusive();
foundElement = body.findText(pattern, foundElement);
}
//Method 2 - locates the text, but I cannot acquire the element object
var body2 = doc.getBody().getText();
var pattern2 = /prior[\s]*written/;
while (m=pattern2.exec(body2))
{
Logger.log(m[0]);
}
}
If this were ever going to work, you would need the regex to be in s (single line) mode. Per https://developers.google.com/apps-script/reference/document/body#findtextsearchpattern,
A subset of the JavaScript regular expression features are not fully supported, such as capture groups and mode modifiers.
So it looks like they have in fact chosen not to support multi-line matches in any way.

Parsing email with Google Apps Script, regex issue?

I used to be quite proficient in VBA with excel, but I'm currently trying to do something with Google Scripts and I am well and truly stuck.
Basically, I am trying like to extract data out of a standardised email from Gmail into a Google sheet. There are a couple of other threads on the subject which I have consulted so far, and I can get the body of the email into the sheet but cannot parse it.
I am new to regex, but it tests OK on regex101
I am also brand new to Google Script, and even the debugger seems to have stopped working now (it did before, so would be grateful if anyone can suggest why this is).
Here is my basic function:
function processInboxToSheet() {
var label = GmailApp.getUserLabelByName("NEWNOPS");
var threads = label.getThreads();
// Set destination sheet
var sheet = SpreadsheetApp.getActiveSheet();
// Get all emails labelled NEWNOPS
for (var i = 0; i < threads.length; i++) {
var tmp,
message = threads[i].getMessages()[1], // second message in thread
content = message.getPlainBody(); // remove html markup
if (content) {
// search email for 'of:' and capure next line of text as address
// tests OK at regex101.com
property = content.match(/of:[\n]([^\r\n]*)[\r\n]/);
// if no match, display error
var property = (tmp && tmp[1]) ? tmp[1].trim() : 'No property';
sheet.appendRow([property]);
} // End if
// remove label to avoid duplication
threads[i].removeLabel(label)
} // End for loop
}
I can append 'content' to the sheet Ok, but cannot extract the address text required by the regex. Content displays as follows:
NOPS for the purchase of:
123 Any Street, Anytown, AN1 1AN
DATE: 05/05/2017
PRICE: £241,000
Seller’s Details
NAME: Mrs Seller
Thanks for reading :)
The return value of .match() is an array. The first captured group, containing the address, will be at index 1.
Based on the following line after your call to .match(), it looks like the tmp variable should have been assigned that array, not the property variable.
var property = (tmp && tmp[1]) ? tmp[1].trim() : 'No property';
That line says, if .match() returned something that isn't null and has a value at index 1, then trim that value and assign to property, otherwise assign it the string 'No property'.
So, try changing this line:
property = content.match(/of:[\n]([^\r\n]*)[\r\n]/);
To this:
tmp = content.match(/of:[\n]([^\r\n]*)[\r\n]/);
Thanks Kevin, I think I must have changed it while debugging.
The problem was with my regexp in the end. After a bit of trial and error the following worked:
tmp = content.match(/of:[\r\n]+([^\r\n]+)/);

actionscript find and convert text to url [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How do I linkify text using ActionScript 3
I have this script that grabs a twitter feed and displays in a little widget. What I want to do is look at the text for a url and convert that url to a link.
public class Main extends MovieClip
{
private var twitterXML:XML; // This holds the xml data
public function Main()
{
// This is Untold Entertainment's Twitter id. Did you grab yours?
var myTwitterID= "username";
// Fire the loadTwitterXML method, passing it the url to your Twitter info:
loadTwitterXML("http://twitter.com/statuses/user_timeline/" + myTwitterID + ".xml");
}
private function loadTwitterXML(URL:String):void
{
var urlLoader:URLLoader = new URLLoader();
// When all the junk has been pulled in from the url, we'll fire finishedLoadingXML:
urlLoader.addEventListener(Event.COMPLETE, finishLoadingXML);
urlLoader.load(new URLRequest(URL));
}
private function finishLoadingXML(e:Event = null):void
{
// All the junk has been pulled in from the xml! Hooray!
// Remove the eventListener as a bit of housecleaning:
e.target.removeEventListener(Event.COMPLETE, finishLoadingXML);
// Populate the xml object with the xml data:
twitterXML = new XML(e.target.data);
showTwitterStatus();
}
private function addTextToField(text:String,field:TextField):void{
/*Regular expressions for replacement, g: replace all, i: no lower/upper case difference
Finds all strings starting with "http://", followed by any number of characters
niether space nor new line.*/
var reg:RegExp=/(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
//Replaces Note: "$&" stands for the replaced string.
text.replace(reg,"$&");
field.htmlText=text;
}
private function showTwitterStatus():void
{
// Uncomment this line if you want to see all the fun stuff Twitter sends you:
//trace(twitterXML);
// Prep the text field to hold our latest Twitter update:
twitter_txt.wordWrap = true;
twitter_txt.autoSize = TextFieldAutoSize.LEFT;
// Populate the text field with the first element in the status.text nodes:
addTextToField(twitterXML.status.text[0], twitter_txt);
}
If this
/(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig
is your regexp for converting text to urls, than i have some remarks.
First of all, almost all characters in chacacter classes are parsed literally.
So, here
[-A-Z0-9+&##\/%?=~_|!:,.;]
you say to search any of this characters (except /).
Simple regexp for url search will look similar to this
/\s((https?|ftp|file):\/\/)?([-a-z0-9_.:])+(\?[-a-z0-9%_?&.])?(\s+|$)/ig
I'm not sure, if it will process url borders right, but \b symbol can be a dot, so i think \s (space or linebreak) will suit better.
I`m not sure about ending (is it allowed in actionscript to use end-of-string symbol not at the end of regexp?)
And, of course, you have to tune it to suit your data.