User:VasilievVV/LinkyParser.php
Initially wasn't supposed to be published. But HardDisk asked it :). Distributed under GPL 2 terms.
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using WikiTools.Access;
namespace LinkyParser
{
/// <summary>
/// Class to parse links in IRC messages
/// </summary>
public class LinkyParser
{
Wiki w;
public string Channel;
public LinkyParser(Wiki w)
{
this.w = w;
w.LoadInterwikis();
}
int curpos = 0;
string curstr = "";
char cc = '\0'; //Current symbol
public static bool IsValidTitleChar(char c)
{
//From DefaultSettings.php
return Regex.IsMatch( new string(c, 1), "[ %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\u0080-\\uFFFF+]", RegexOptions.IgnoreCase );
}
public static string NormalizeTitle(string s)
{
if( s == "")
return s;
s = s.Replace('_', ' ');
if( Char.IsLetter( s[0] ) )
s = Char.ToUpper( s[0] ) + s.Substring(1);
return s;
}
public void Parse(string str)
{
int linkcount = 0;
curpos = 0;
curstr = str;
if( str.Length == 0 )
return;
cc = str[0];
StringBuilder ctitlestr = null, cfragmentstr = null;
if(str.Contains("@nl@") )
return;
do
{
if( cc == '[' && NextChar() && cc == '[' && NextChar() )
{
ctitlestr = new StringBuilder();
cfragmentstr = new StringBuilder();
bool isFragment = false;
bool skipchars = false;
do
{
if( cc == ']' && NextChar() && cc == ']')
{
linkcount++;
if( linkcount > 3 )
break;
if( Callback != null )
Callback( this as object, NormalizeTitle( ctitlestr.ToString().Trim() ) );
if( UriCallback != null )
CallUriCallback( ctitlestr.ToString().Trim(),
cfragmentstr.ToString().Trim() );
break;
}
if( cc == '|' ) skipchars = true;
if( cc == '#' ) {
isFragment = true;
}
if( IsValidTitleChar( cc ) ) {
if( !skipchars ) {
if( isFragment ) {
cfragmentstr.Append(cc);
} else {
ctitlestr.Append(cc);
}
}
}
}
while( NextChar() );
//Ok, we're out of string. Perhaps it's something like "[[Test". Just ignore it
}
if( cc == '{' && NextChar() && cc == '{' && NextChar() &&
cc == 't' && NextChar() && cc == 'l' && NextChar() &&
cc == '|' && NextChar() )
{
ctitlestr = new StringBuilder();
do
{
if( cc == '}' && NextChar() && cc == '}')
{
linkcount++;
if( linkcount > 3 )
break;
if( Callback != null )
Callback( this as object, w.NamespacesUtils.GetNamespaceByID(Namespaces.Template)
+ ":" + NormalizeTitle( ctitlestr.ToString().Trim() ) );
if( UriCallback != null )
CallUriCallback( w.NamespacesUtils.GetNamespaceByID(Namespaces.Template)
+ ":" + ctitlestr.ToString().Trim(), null );
break;
}
if( IsValidTitleChar( cc ) )
ctitlestr.Append(cc);
}
while( NextChar() );
//Ok, we're out of string. Perhaps it's something like "[[Test"
}
}
while( NextChar() );
}
public bool NextChar()
{
curpos++;
if (curpos >= curstr.Length)
return false;
cc = curstr[curpos];
return true;
}
public void CallUriCallback(string title, string fragment) {
UriCallback( this as object, FormatUri( title, fragment ) );
}
public string FormatUri(string title, string fragment) {
foreach( InterwikiMapEntry entry in w.Interwikis ) {
if( title.StartsWith( entry.Prefix + ":" ) ) {
return entry.Uri.Replace( "$1",
EscapeTitleForUri( title.Substring(entry.Prefix.Length + 1) ) );
}
}
string frag = "";
if( !String.IsNullOrEmpty( fragment ) ) {
frag = "#" + EscpaeFragment( fragment );
}
return w.WikiURI.Replace("/w", "/wiki/") + EscapeTitleForUri(title) + frag;
}
public static string EscapeTitleForUri(string title) {
//title = title.Replace("%", Uri.EscapeDataString("%"));
title = title.Replace(" ", "_");
title = title.Replace("?", Uri.EscapeDataString("?"));
return title;
}
public static string EscpaeFragment(string f) {
f = Uri.EscapeDataString( f );
f = f.Replace( "%", "." );
f = f.Replace( ".20", "_" );
f = f.Replace( ".3A", ":" );
return f;
}
public event LinkyCallback Callback;
public event LinkyCallback UriCallback;
}
public delegate void LinkyCallback(object sender, string name);
}